Spring AOP总结

Spring AOP的重要对象

Spring AOP的参与者。

切面(Aspect): 一个关注点的模块化,这个模块会横切多个对象。Spring中使用org.springframework.aop.Advisor作切面。

连接点(Joinpoint): 程序执行过程中明确的点,如方法的调用或特定的异常被抛出。Spring中使用org.aspectj.lang.JoinPoint为连接点对象。

切点(Pointcut): 指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。 Spring使用MethodMatcher和ClassFilter来组合Pointcut接口,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上。

通知或增强(Advice):“切面”对于某个“连接点”所产生的动作。Spring中通过org.aopalliance.aop包下的Advice或者MethodInterceptor接口实现。

目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象。

AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。 在Spring中,AOP代理通过JDK动态代理技术或者CGLIB代理技术创建。


Spring的增强类型

(1)类级别的有引介增强。

在Spring中使用org.springframework.aop.IntroductionAdvisor来实现引介增强,通过org.springframework.aop.IntroductionInterceptor接口提供增强内容。

(2)方法级别的增强

1)前置增强:通过org.springframework.aop.MethodBeforeAdvice接口实现。Spring提供了org.springframework.aop.aspectj.AspectJMethodBeforeAdvice用于实现AspectJ语言中@Before注解和aop命名空间的<before>标签表示的前置增强。

2)后置增强和环绕增强:通过org.aopalliance.intercept.MethodInterceptor接口实现。Spring提供了org.springframework.aop.aspectj.AspectJAfterAdvice用于表示AspectJ语言中@After注解和aop命名空间的<after>标签表示的后置增强,org.springframework.aop.aspectj.AspectJAroundAdvice用于表示AspectJ语言中@Around注解和aop命名空间的<around>标签表示的环绕增强。

3)异常后增强:使用org.springframework.aop.ThrowsAdvice接口实现。Spring提供org.springframework.aop.aspectj.AspectJAfterThrowingAdvice用于表示AspectJ语言中@AfterThrowing注解和aop命名空间的<after-throwing>标签表示的异常后增强。

4)返回后增强:使用org.springframework.aop.AfterReturningAdvice接口实现。Spring中通过org.springframework.aop.aspectj.AspectJAfterReturningAdvice用于表示AspectJ语言中@AfterReturning注解和aop命名空间的<after-returning>标签表示的返回后增强。

下面是各个增强类型的执行顺序图
这里写图片描述

Spring AOP的执行过程使用责任链模式,通常使用org.aopalliance.intercept.MethodInvocation接口的实现类(如CglibMethodInvocation和ReflectiveMethodInvocation)维护责任链的执行过程。责任链上每个责任的处理接口为org.aopalliance.intercept.MethodInterceptor,每个Advice都对应一个MethodInterceptor实现。因此,不管是哪种类型的Advice,都可以通过org.aopalliance.intercept.MethodInterceptor来实现。


Spring的切点类型

(1)静态方法切点:

通过抽象类org.springframework.aop.support.StaticMethodMatcher的子类提供,它有两个主要的子类分别是NameMatchMethodPointcut和JdkRegexpMethodPointcut,前者通过提供简单字符串匹配方法签名,后者通过正则表达式匹配方法签名。

(2)动态方法切点:

通过抽象类org.springframework.aop.support.DynamicMethodMatcherPointcut的子类提供。

(3)注解切点:

通过org.springframework.aop.support.annotation.AnnotationMatchingPointcut类提供,它其实也是一个静态方法切点。通过它可以匹配被某一注解对象标注的方法。

(4)表达式切点:

通过 org.springframework.aop.support.ExpressionPointcut接口的实现类提供。它的主要实现类AspectJExpressionPointcut用于支持AspectJ表达式。

(5)流程切点:

通过 org.springframework.aop.support.ControlFlowPointcut类提供。它通过程序执行堆栈信息查看目标方法是否由某一个方法直接或间接发起调用,以此判断是否为匹配的连接点。使用这个切点会有性能损耗。

(6)复合切点:

通过org.springframework.aop.support.ComposablePointcut类创建多个切点。


Spring的切面类型

(1)Advisor

代表一般切面,它仅保护一个Advice对象。由于Advice既包含横切代码,也包含连接点信息(方法前、后等),所以一个Advice对象就是一个简单的切面,只是它所代表的横切连接点是目标类的所有方法,因此这个横切面的范围太广,一般不会直接使用。

(2)PointcutAdvisor

代表具有切点的切面,包含Advice和Pointcut两个对象。Spring提供如下几个切面类。
1)org.springframework.aop.support.DefaultPointcutAdvisor:最常用最普通的切面类型,它可以通过任意的Advice和Pointcut定义一个切面,但不能定义引介切面。一般可以扩展它来自定义一个切面。

2)org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor:和DefaultPointcutAdvisor一样,它可以通过任意的Advice和Pointcut定义一个切面。只是它可以通过Advice的名称从Spring容器中获取对应的Advice对象。

3)org.springframework.aop.support.RegexpMethodPointcutAdvisor:使用正则表达式匹配方法名创建一个切点来定义一个切面,其内部使用JdkRegexpMethodPointcut作为切点对象,也可以扩展该Advisor指定其它类型的正则表达式。

4)org.springframework.aop.support.NameMatchMethodPointcutAdvisor:通过方法名称匹配来创建一个切点来定义一个切面,其内部使用NameMatchMethodPointcut作为切点对象。

5)org.springframework.aop.aspectj.AspectJPointcutAdvisor:通过AspectJ语法定义一个切面,它的创建需要提供一个内部包含了AspectJExpressionPointcut切点对象的AbstractAspectJAdvice通知对象。

6)org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor:通过AspectJ表达式定义一个切面,其内部使用AspectJExpressionPointcut作为切点对象。

(3)IntroductionAdvisor

代表引介切面。Spring定义了如下两个切面。

1) org.springframework.aop.support.DefaultIntroductionAdvisor:这是一个最基本的引介切面,它接受任意的Advice和IntroductionInfo对象定义一个引介切面,只是它增强的目标类是所有类。

2) org.springframework.aop.aspectj.DeclareParentsAdvisor:它通过指定能够匹配目标类的AspectJ类型匹配模式表达式和需添加的接口及其实现类来定义一个引介切面,它的内部使用DelegatePerTargetObjectIntroductionInterceptor或DelegatingIntroductionInterceptor增强对象。在Spring中,DeclareParentsAdvisor是org.aspectj.lang.annotation.DeclareParents注解默认表示的引介切面。


Spring中如何使用AOP

(1)使用Spring AOP的基本步骤

这里写图片描述

1)创建通知,实现org.aopalliance.aop包下的Advice或者MethodInterceptor接口
2)创建切点,使用Spring定义的切点或者实现org.springframework.aop.Pointcut接口创建自定义的切点。
3)创建切面,使用Spring定义的Advisor类,或者实现org.springframework.aop.Advisor接口创建自定义切面。
4)通过JDK动态代理或者Cglib代理创建代理对象

(2)Spring中AOP的使用方式

1 通过XML配置有4中方式:

这里写图片描述
1)纯手工配置ProxyFactoryBean,手动设置target(被代理对象)、Advisor(通知者、切面)、Advice(通知)和Pontcut(切点)。使用这种方式时,通过ProxyFactoryBean的bean名称获取代理bean。

2)AOP自动代理,配置AbstractAutoProxyCreator的子类,如AnnotationAwareAspectJAutoProxyCreator、AspectJAwareAdvisorAutoProxyCreator等。使用这种方式下,bean的获取和以前一样,但获取的bean已经是代理bean了。

3)通过<aop:config>来配置。

4) 通过<aop: aspectj-autoproxy>来配置,使用AspectJ的注解来标识通知及切入点。

前面两种方式可以方便我们更深入的了解Spring AOP的原理,其中第二种方式还可以方便我们了解Spring AOP自动代理的原理;

在项目中通常使用<aop:config>和<aop: aspectj-autoproxy>来做AOP的配置。因为这种两种方式方便、简单,不会造成xml内容过于臃肿而造成配置难于维护。这两种方式不仅使用了自动代理,还把Pointcut、Advisor甚至是Advice的创建任务都交给Spring框架来完成。

2 通过Java编程的方式。

使用ProxyFacotry,这也是在Spring AOP自动代理,即AbstractAutoProxyCreator抽象类的源码中,默认使用的。
通过ProxyFactory的addAdvisor方法添加Advisor、setTargetSource方法设置target等,然后通过ProxyFactory的getProxy方法获得代理对象。


Spring AOP创建代理对象的时机

(1)ProxyFactoryBean

ProxyFactoryBean实现了FactoryBean接口,当调用它的getObject()方法时就会为bean创建代理对象。

(2)Spring AOP自动代理

对于AbstractAutoProxyCreator类,它实现了SmartInstantiationAwareBeanPostProcessor接口,并且作为AOP自动代理默认使用的后处理器,在以下时间点将会调用它的相应接口方法创建代理:

1)bean实例化前
调用AbstractAutoProxyCreator的postProcessBeforeInstantiation方法通过自定义的TargetSourceCreator创建bean的TargetSource,如果在这里bean的TargetSource存在,则创建相应的代理并完成bean的创建。

2)单例bean实例化后
Spring会为其创建一个FactoryBean对象,在程序获取这个bean时FactoryBean会调用AbstractAutoProxyCreator的getEarlyBeanReference方法创建Bean的代理对象。

3)bean的属性初始化完成后
调用AbstractAutoProxyCreator的postProcessAfterInitialization方法为应该创建代理而还没有创建代理的bean(比如作用域为prototype的bean)创建代理对象。

展开阅读全文

Spring AOP报错,好久好久都没解决,快疯了

09-10
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.config.internalAutoProxyCreator': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/core/convert/converter/ConvertingComparator at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:965) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:911) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:710) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:410) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83) at gxa4.APP.main(APP.java:16) Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/core/convert/converter/ConvertingComparator at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:141) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:74) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:958) ... 12 more Caused by: java.lang.NoClassDefFoundError: org/springframework/core/convert/converter/ConvertingComparator at org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.<clinit>(ReflectiveAspectJAdvisorFactory.java:74) at org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.<init>(AnnotationAwareAspectJAutoProxyCreator.java:53) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:126) ... 14 more Caused by: java.lang.ClassNotFoundException: org.springframework.core.convert.converter.ConvertingComparator at java.net.URLClassLoader$1.run(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) ... 21 more
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值