Spring AOP详解(示例)
2017-08-14 15:00
351 查看
一、什么是AOP
AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与 OOP( Object-Oriented Programming, 面向对象编程) 相辅相成, 提供了与 OOP 不同的抽象软件结构的视角.在 OOP 中, 我们以类(class)作为我们的基本单元, 而 AOP 中的基本单元是 Aspect(切面)。
二、AOP的优点
它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即切面。所谓“切面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
三、AOP的相关术语
1.通知(Advice):
所谓通知指的就是指拦截到连接点之后要执行的代码(比如我们拦截到用户点击登录事件,然后我们需要判断登录的账号密码是否合法,是否合法的逻辑就在Advice的方法中实现,也就是拦截到连接到后要做什么处理,都在这里实现),通知分为前置、后置、异常、最终、环绕通知五类。
2.连接点(Joinpoint):
用于定义通知(Advice)应该切入到哪些连接点(JoinPoint)上。不同的通知通常需要切入到不同的连接点上,一般为一个方法。
3.切入点(Pointcut):
通知定义了切面要发生的“故事”和时间(定义了what和when),那么切入点就定义了“故事”发生的地点(where),例如某个类或方法的名称,spring中允许我们方便的用正则表达式来指定。
4.切面(Aspect):
通知和切入点共同组成了切面,切面可能包含很多切入点
5.织入(Weaving):
组装切面来创建一个被通知对象。
完成时机:可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
6.引入(Introduction)
引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)
7.目标(Target)
即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事)
8.代理(proxy)
应用通知的对象
三、基于XML配置的AOP实例
上面的概念主要用于理解,网上很多,可以自己去理解。下面主要来用实例演示SpringAOP。
1.添加所需的jar包(可以使用maven依赖仓库帮你下载,我这里就自己一个个下载的)
注意:不能少了aspectjweaver包,否则会报错
2.创建项目(SpringAOPTest)
代码没什么业务逻辑只是一些打印操作,这里把代码贴出来。
HelloWorld(处理业务逻辑)
Logger(横切面关注点)
Test(测试类)
XML配置文件(applicationContext.xml):
运行结果:
四、基于注解的AOP实例
HelloWorld(处理业务逻辑)
Logger(横切面关注点)
Test(测试类)
xml配置文件(applicationContext.xml):
运行结果:
注意:基于注解时需要在xml文件中添加如下代码:
然后aspectjweaver.jar需要更新到最近的版本,不然会因为jdk版本高,aspectjweaver.jar不是最近的造成异常。
五、总结
Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:
1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB,在xml中配置就好。
通过上面的示例发现SpringAOP编程我们需要处理的就是:
1、定义普通业务组件(比如HelloWorld类)
2、定义切入点,一个切入点可能横切多个业务组件(比如Logger类)
3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作
AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与 OOP( Object-Oriented Programming, 面向对象编程) 相辅相成, 提供了与 OOP 不同的抽象软件结构的视角.在 OOP 中, 我们以类(class)作为我们的基本单元, 而 AOP 中的基本单元是 Aspect(切面)。
二、AOP的优点
它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即切面。所谓“切面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
三、AOP的相关术语
1.通知(Advice):
所谓通知指的就是指拦截到连接点之后要执行的代码(比如我们拦截到用户点击登录事件,然后我们需要判断登录的账号密码是否合法,是否合法的逻辑就在Advice的方法中实现,也就是拦截到连接到后要做什么处理,都在这里实现),通知分为前置、后置、异常、最终、环绕通知五类。
2.连接点(Joinpoint):
用于定义通知(Advice)应该切入到哪些连接点(JoinPoint)上。不同的通知通常需要切入到不同的连接点上,一般为一个方法。
3.切入点(Pointcut):
通知定义了切面要发生的“故事”和时间(定义了what和when),那么切入点就定义了“故事”发生的地点(where),例如某个类或方法的名称,spring中允许我们方便的用正则表达式来指定。
4.切面(Aspect):
通知和切入点共同组成了切面,切面可能包含很多切入点
5.织入(Weaving):
组装切面来创建一个被通知对象。
完成时机:可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
6.引入(Introduction)
引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)
7.目标(Target)
即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事)
8.代理(proxy)
应用通知的对象
三、基于XML配置的AOP实例
上面的概念主要用于理解,网上很多,可以自己去理解。下面主要来用实例演示SpringAOP。
1.添加所需的jar包(可以使用maven依赖仓库帮你下载,我这里就自己一个个下载的)
注意:不能少了aspectjweaver包,否则会报错
2.创建项目(SpringAOPTest)
代码没什么业务逻辑只是一些打印操作,这里把代码贴出来。
HelloWorld(处理业务逻辑)
package com.xxx.aop; /** *@description *@author create by xiaoxsen *@date 2017年8月14日---下午1:59:17 */ public class HelloWorld { public void print() { System.out.println("helloworld"); } }
Logger(横切面关注点)
package com.xxx.aop; /** *@author create by xiaoxsen *@date 2017年8月14日---下午12:28:05 */ public class Logger { public void printBefore(){ System.out.println("执行前CurrentTime: "+System.currentTimeMillis()); } public void printAfter(){ System.out.println("执行后CurrentTime: "+System.currentTimeMillis()); } }
Test(测试类)
package com.xxx.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** *@description *@author create by xiaoxsen *@date 2017年8月14日---下午2:00:18 */ public class Test { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld h = (HelloWorld) context.getBean("helloworld"); h.print(); } }
XML配置文件(applicationContext.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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <bean id="helloworld" class="com.xxx.aop.HelloWorld"></bean> <bean id="logger" class="com.xxx.aop.Logger"></bean> <!-- aop配置 --> <aop:config> <!-- 切入点配置 --> <aop:pointcut expression="execution(* com.xxx.aop.HelloWorld.* (..))" id="addPrint"/><!--织入到HelloWorld的所有方法,方法可以自己定制--> <aop:aspect id="log" ref="logger"> <!-- 通知配置 --> <aop:before method="printBefore" pointcut-ref="addPrint"/> <aop:after method="printAfter" pointcut-ref="addPrint"/> </aop:aspect> </aop:config> </beans>
运行结果:
执行前CurrentTime: 1502692311935 helloworld 执行后CurrentTime: 1502692311951
四、基于注解的AOP实例
HelloWorld(处理业务逻辑)
package com.xxx.aop; import org.springframework.stereotype.Service; /** *@description *@author create by xiaoxsen *@date 2017年8月14日---下午1:59:17 */ @Service public class HelloWorld { public void print() { System.out.println("helloworld"); } }
Logger(横切面关注点)
package com.xxx.aop; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** *@author create by xiaoxsen *@date 2017年8月14日---下午12:28:05 */ //指定切面的优先级,当有多个切面时,数值越小优先级越高 @Order(1) //把这个类声明为一个切面:需要把该类放入到IOC容器中。再声明为一个切面. @Aspect @Component public class Logger { /** * 声明切入点表达式,一般在该方法中不再添加其他代码。 * 使用@Pointcut来声明切入点表达式。 * 后面的通知直接使用方法名来引用当前的切入点表达式。 * 后面表达式的方法就是目标方法 */ @Pointcut("execution(* com.xxx.aop.HelloWorld.* (..))") public void declareJoinPointExpression() {} /** *前置通知,在目标方法开始之前执行。 *@Before("execution(*)")这样写可以指定特定的方法比如(public void com.xxx.aop.HelloWorld.print())。 * @param joinpoint */ @Before("declareJoinPointExpression()") public void printBefore(){ System.out.println("执行前CurrentTime: "+System.currentTimeMillis()); } /** *前置通知,在目标方法开始之后执行。 *@after("execution(*)")这样写可以指定特定的方法比如(public void com.xxx.aop.HelloWorld.print())。 * @param joinpoint */ @After("declareJoinPointExpression()") public void printAfter(){ System.out.println("执行后CurrentTime: "+System.currentTimeMillis()); } }
Test(测试类)
package com.xxx.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** *@description *@author create by xiaoxsen *@date 2017年8月14日---下午2:00:18 */ public class Test { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld h = (HelloWorld) context.getBean(HelloWorld.class); h.print(); } }
xml配置文件(applicationContext.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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" > <!-- 配置自动扫描包 --> <context:component-scan base-package="com.xxx.aop"></context:component-scan> <!-- 使AspectJ注解起作用:自动为匹配的类生产代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
运行结果:
执行前CurrentTime: 1502703074952 helloworld 执行后CurrentTime: 1502703074970
注意:基于注解时需要在xml文件中添加如下代码:
<context:component-scan base-package="com.xxx.aop"></context:component-scan> <!-- 使AspectJ注解起作用:自动为匹配的类生产代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
然后aspectjweaver.jar需要更新到最近的版本,不然会因为jdk版本高,aspectjweaver.jar不是最近的造成异常。
五、总结
Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:
1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB,在xml中配置就好。
通过上面的示例发现SpringAOP编程我们需要处理的就是:
1、定义普通业务组件(比如HelloWorld类)
2、定义切入点,一个切入点可能横切多个业务组件(比如Logger类)
3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作
相关文章推荐
- spring中AOP 注解开发示例详解
- spring中AOP 注解开发示例详解
- spring AOP 代理机制、执行过程、四种实现方式及示例详解
- Spring AOP拦截-三种方式实现自动代理详解
- Spring3.0 AOP 详解
- Spring4.3x教程之三AOP详解
- Spring 技术核心 IOC AOP <二> AOP详解
- Spring AspectJ AOP 完整示例
- Spring 之AOP AspectJ切入点语法详解(最全面、最详细。)(转)
- Spring 之AOP AspectJ切入点语法详解
- SSH中各个框架的作用以及Spring AOP,IOC,DI详解
- Spring aop学习示例
- Spring解密之XML解析与Bean注册示例详解
- springboot配置aop切面详解
- Spring 中AOP 特性详解
- 详解Spring Aop 拦截 Struts2 Action 出现的异常
- 详解SpringBoot AOP 拦截器(Aspect注解方式)
- Spring3.0 AOP 详解
- »Spring 之AOP AspectJ切入点语法详解(最全了,不需要再去其他地找了)
- Spring笔记(三):Aop详解