1. 什么是AOP?
  2. AOP基本概念
  3. AOP使用--注解方式
  4. AOP使用--XML方式
  5. 实例--日志

  

  写在最前面的(源码地址):

    https://github.com/xc83415134/spring_aop_demo

一、什么是AOP?

  AOP(Aspect Oriented Programmin)即面向切面编程(或者翻译成以切面为导向的编程模式?),一种OOP延续的编程思想,将系统中非核心业务提取出来,从而将其与其所影响的对象解耦,切面就是提取出来的功能模块。切面可以帮助我们模块化横切关注点,常见的有日志、安全、事物等。

  对于一个信用卡应用程序来说,存款、取款、帐单管理是它的主关注点,日志和持久化将成为横切整个对象结构的横切关注点。

二、AOP基本概念

以下为维基百科部分说明:

关注点(concern):对软件工程有意义的小的、可管理的、可描述的软件组成部分,一个关注点通常只同一个特定概念或目标相关联。
主关注点(core concern):一个软件最主要的关注点。
关注点分离(separation of concerns,SOC):标识、封装和操纵只与特定概念、目标相关联的软件组成部分的能力,即标识、封装和操纵关注点的能力。
方法(method):用来描述、设计、实现一个给定关注点的软件构造单位。
横切(crosscut):两个关注点相互横切,如果实现它们的方法存在交集。
支配性分解(dominant decomposition):将软件分解成模块的主要方式。传统的程序设计语言是以一种线性的文本来描述软件的,只采用一种方式(比如:类)将软件分解成模块;这导致某些关注点比较好的被捕捉,容易进一步组合、扩展;但还有一些关注点没有被捕捉,弥散在整个软件内部。支配性分解一般是按主关注点进行模块分解的。
横切关注点(crosscutting concerns):在传统的程序设计语言中,除了主关注点可以被支配性分解方式捕捉以外,还有许多没有被支配性分解方式捕捉到的关注点,这些关注点的实现会弥散在整个软件内部,这时这些关注点同主关注点是横切的。
侧面(aspect):在支配性分解的基础上,提供的一种辅助的模块化机制,这种新的模块化机制可以捕捉横切关注点。
从主关注点中分离出横切关注点是面向侧面的程序设计的核心概念。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通过侧面来封装、维护,这样原本分散在在整个应用程序中的变动就可以很好的管理起来。

三、AOP使用--注解方式

  1.启用AOP

  以下为启用AspectJ自动代理,同时需声明Spring aop 命名空间(注意标红的部分)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><context:annotation-config /><context:component-scan base-package="foo.bar"/><!--启用aspectj自动代理--><aop:aspectj-autoproxy />
</beans>

  2.定义被监听类

  普通的类,待监听对象无特殊

package foo.bar.observed;import org.springframework.stereotype.Component;/*** Created by xuc on 2018/1/16.* 说话的人A*/
@Component
public class HelloByAnnotation {public void sayHello(String arg) {System.out.println(arg);}
}

  3.定义切面

  首先加入@Component注解,让spring扫描到,注入spring容器中。加入@Aspect注解,声明其为切面,再通过@Pointcut注解表面某一方法为切点,(括号内:execution表明为在方法执行时触发,*为返回任意类型,后面紧跟的为指定方法,String为接收参数类型,&&表示并且,arg为接收的参数)。其他注解:

注解 通知
@After 通知方法在目标方法返回或抛出异常后调用
@AfterReturning 通知方法在目标方法返回后调用
@AfterThrowing 通知方法在目标方法抛出异常后
@Around 通知方法在目标方法封装起来
@Before 通知方法在目标方法调用前执行
package foo.bar.observer;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;/*** Created by xuc on 2018/1/16.** 大脑活动* 执行顺序:*   {@link Around} -> {@link Before} -> 目标方法 -> {@link Around}*        -> {@link After}*        -> {@link AfterReturning} 或 {@link AfterThrowing}*/
@Component
@Aspect
public class brain {/*** 定义切点* *:返回任意* *.sayHello:指定方法* String:指定接收类型* arg:指定接收参数*/@Pointcut("execution(* foo.bar.observed.HelloByAnnotation.sayHello(String)) && args(arg)")public void speak(String arg){}/*** 目标方法调用前执行*/@Before("speak(arg)")public void think(String arg){System.out.println("1.说话前要注意三思而后行:" + arg);}/*** 目标方法返回后执行*/@AfterReturning("speak(arg)")public void listen(String arg){System.out.println("2.说完后要虚心接受长辈的教诲");}/*** 目标方法抛出异常后*/@AfterThrowing("speak(arg)")public void reflection(String arg){System.out.println("3.说错话后要反思为什么");}/*** 目标方法前、后执行两次*/@Around("speak(arg)")public void doThings(ProceedingJoinPoint joinPoint, String arg) throws Throwable {System.out.println("4.准备干点其他事");joinPoint.proceed();System.out.println("4.其他事做完");}
}

  4.执行main测试(执行前,可以先看下第5步)

package foo.bar;import foo.bar.observed.HelloByAnnotation;
import foo.bar.observed.IDeclareHello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class HelloApp {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");excuteByAnnotion(context);}/*** 基于注解配置* @param context*/private static void excuteByAnnotion(ApplicationContext context) {HelloByAnnotation helloByAnnotation = context.getBean(HelloByAnnotation.class);helloByAnnotation.sayHello("Hello world!  -- by annotation");IDeclareHello declareHello = (IDeclareHello)helloByAnnotation;declareHello.sayBye();}
}

  5.通过注解引入新功能

  通过aop对原类进行功能加强(装饰模式),即可以动态的对一个类添加方法(有意思不?)。

  定义一个普通的接口和实现类:

package foo.bar.observed;/*** Created by xuc on 2018/1/16.*/
public interface IDeclareHello {void sayBye();
}
package foo.bar.observed;import org.springframework.stereotype.Component;/*** Created by xuc on 2018/1/16.** {@link HelloByAnnotation} 的装饰类,为其添加方法*/
@Component
public class DeclareHello implements IDeclareHello{public void sayBye(){System.out.println("执行再见方法:Bye!");}
}

  定义一个切面,再通过@DeclareParents注解(就当她是个媒婆,撮合原类和加强类,哈哈哈哈...),value为原类(男方),变量为加强接口(女方),最后就可以生娃娃了……^.^

package foo.bar.declaretion;import foo.bar.observed.DeclareHello;
import foo.bar.observed.IDeclareHello;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;/*** Created by xuc on 2018/1/16.** 将{@link DeclareHello}介绍给{@link HelloIntroducer}* 这是一种装饰模式,是对原类的加强*/
@Component
@Aspect
public class HelloIntroducer {@DeclareParents(value = "foo.bar.observed.HelloByAnnotation", defaultImpl = DeclareHello.class)public static IDeclareHello declareHello;
}

  四、AOP使用--XML方式

  与上面的基于注解方式无异,只是切面定义无需破坏原代码,可以再XML中实现,下面简单说明下。

  1.定义一个普通的类,待监听对象

package foo.bar.observed;import org.springframework.stereotype.Component;/*** Created by xuc on 2018/1/17.*/
@Component
public class HelloByXml {public void sayHello(String arg) {System.out.println(arg);}
}

  2.再定义一个普通的类,切面类(对,切面累,不是切糕累。。),无需声明其为切面

package foo.bar.observer;import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;/*** Created by xuc on 2018/1/17.* 小脑活动*/
@Component
public class Cerebellum {public void think(String arg){System.out.println("1.说话前要注意三思而后行:" + arg);}/*** 目标方法返回后执行*/public void listen(String arg){System.out.println("2.说完后要虚心接受长辈的教诲s");}/*** 目标方法抛出异常后*/public void reflection(String arg){System.out.println("3.说错话后要反思为什么");}/*** 目标方法前、后执行两次*/public void doThings(ProceedingJoinPoint joinPoint, String arg) throws Throwable {System.out.println("4.准备干点其他事");joinPoint.proceed();System.out.println("4.其他事做完");}
}

  3.XML配置切面

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><context:annotation-config /><context:component-scan base-package="foo.bar"/><!--启用aspectj自动代理--><aop:aspectj-autoproxy /><!-- XML方式 演示--><!--此处仅列举一个前置通知,其他与注解形式类似--><aop:config><aop:aspect ref="cerebellum"><aop:pointcut id="speak" expression="execution(* foo.bar.observed.HelloByXml.sayHello(String)) and args(arg)"/><aop:before method="think" pointcut-ref="speak"/></aop:aspect></aop:config>
</beans>

  4.执行main测试

package foo.bar;import foo.bar.observed.HelloByAnnotation;
import foo.bar.observed.HelloByXml;
import foo.bar.observed.IDeclareHello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class HelloApp {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");excuteByXml(context);}/*** 基于XML配置* @param context*/private static void excuteByXml(ApplicationContext context) {HelloByXml helloByXml = context.getBean(HelloByXml.class);helloByXml.sayHello("Hello world!  -- by xml");}
}

  五、实例--日志

  以上为Spring AOP的基本使用方法,下面举一个实际开发的例子,基于自定义注解与切面结合实现异步日志入库(实际上也是个小例子。。。)。

  1.定义一个注解

package foo.bar.annotation;import java.lang.annotation.*;/*** Created by xuc on 2018/1/18.* 日志生成注解(切点)*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface PrintLog {int type();
}

  2.定义一个切面,声明上面的注解为其切点

package foo.bar.annotation;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;/*** Created by xuc on 2018/1/18.*/
@Aspect
@Component
public class PrintLogOperation {@Around("within(foo.bar.observed..*) && @annotation(printLog)")public void offerMailPo(ProceedingJoinPoint jp, PrintLog printLog) throws Throwable {if (printLog.type() == 0){System.out.println("你好啊,我是一条日志...");}jp.proceed();}
}

 

环境: IDEA、Spring4.0
参考资料: 《spring实战》

spring使用之旅(二) ---- AOP的使用相关推荐

  1. Spring学习之旅(二) AOP(面向切面编程)的使用

    辛苦堆砌,转载请注明出处,谢谢! 上一篇说了Spring的依赖注入,今天再看看Spring的AOP,牵扯的AOP的理论知识,大家可以搜索一些文章了解一下,这里不做过多解释,本文主要介绍使用Spring ...

  2. Spring 源码分析(三) —— AOP(二)Spring AOP 整体架构

    2019独角兽企业重金招聘Python工程师标准>>> Spring AOP 架构         先是生成代理对象,然后是拦截器的作用,最后是编织的具体实现.这是AOP实现的三个步 ...

  3. Spring学习(八)AOP详解

    本文借鉴:Spring学习 一.一个例子 在上面的例子中,包租婆的核心业务就是签合同,收房租,那么这就够了,灰色框起来的部分都是重复且边缘的事,交给中介商就好了,这就是 AOP 的一个思想:让关注点代 ...

  4. Spring 框架基础(04):AOP切面编程概念,几种实现方式演示

    本文源码:GitHub·点这里 || GitEE·点这里 一.AOP基础简介 1.切面编程简介 AOP全称:Aspect Oriented Programming,面向切面编程.通过预编译方式和运行期 ...

  5. Spring学习笔记专题二

    专题二 (1)注解 1,注解的作用:给Java结构添加标记: 2,注解的使用:使用注解一般需要三方面参与: 1,注解类: 2,需要标记的目标类型: 3,用于处理目标类型的处理程序: 3,Retenti ...

  6. (转)使用Spring的注解方式实现AOP的细节

    http://blog.csdn.net/yerenyuan_pku/article/details/52879669 前面我们已经入门使用Spring的注解方式实现AOP了,现在我们再来学习使用Sp ...

  7. Spring源码分析之AOP源码分析

    文章目录 前言 一.AOP回顾 二.源码分析 EnableAspectJAutoProxy注解 AnnotationAwareAspectJAutoProxyCreator 前言 Spring框架的两 ...

  8. Spring总结(IOC、AOP原理以及Spring事务)

    一.概述 1.Spring是一个开源免费且轻量级的框架 , 非侵入式的 . 2.控制反转 IoC , 面向切面 Aop 3 .对事物的支持 , 对框架的支持 一句话概括: Spring 是一个轻量级的 ...

  9. spring面试题(二)

    目录 硅谷 一 .请写出 spring 中常用的依赖注入方式. 二  .简述Spring中IOC容器常用的接口和具体的实现类 三 .简述Spring中如何基于注解配置Bean和装配Bean 四.  说 ...

  10. 【Spring】面向切面编程AOP

    AOP基础 什么是AOP [废话解释]在软件业,AOP全称Aspect Oriented Programming 即:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AO ...

最新文章

  1. HDU 2444 The Accomodation of Students (二部图+染色)
  2. linux导出并追加到文件,linux – 如何将awk结果输出到文件
  3. 用nrm一键切换npm源
  4. 用友二次开发 用友控件 Js宿主脚本 调用用友T6 登录 参照 控件示例
  5. 手工xxoo Visual Assist X 笔记
  6. 20175221曾祥杰 实验四《Android程序设计》
  7. 奥巴马访华:不建议过度审查 提倡加强互联网开放
  8. 苹果cms10 官方QQ微信防红防封代码
  9. [RMAN]数据文件的恢复
  10. 【腾讯内部干货分享】分析Dalvik字节码进行减包优化
  11. mysql可以建立个人数据库吗_mysql怎么建立数据库?
  12. 2022新版UI云购H5系统源码+完美运行/功能强大
  13. 微博营销的价值与注意点
  14. EXCEL技术VBA一键获取SAP系统数据
  15. 微信小程序app.json全局配置项
  16. SS524V100 SDK安装编译osdrv问题汇总
  17. 通用Excel数据导入功能模板
  18. Vue使用Router报错:ncaught ReferenceError: VueRouter is not defined
  19. 【Niagara 04】Tridium N4使用——生成报警信息
  20. SignalTap II 之 Power-Up Trigger

热门文章

  1. 玩转SpringCloud(F版本) 四.路由网关(zuul)
  2. pandas删除最后一列_Python中pandas dataframe删除一行或一列:drop函数详解
  3. highcharts 开发笔记
  4. ByteV打造智慧建筑可视化管理平台——IBMS智能化集成系统赋予楼宇“智慧大脑
  5. 解决Outlook搜索功能的搜索结果不完整问题
  6. Fortinet:网络安全越来越勤快,可甲方却应该越来越「懒」
  7. TL431-精密基准电压源
  8. 三个“清洁代码”技巧将使您的开发团队效率提高 50%
  9. Java实现:挖金矿问题
  10. pycharm条件判断