大白话:在方法执行前后运行指定代码,比如日志记录、事务开启/提交/回滚等。为什么要AOP?
大白话:增强原方法的功能,解耦通用功能,透明化静默操作。
举例 事务切面切面:
增强原方法的功能:原本方法使用的是数据库连接默认的策略自动提交事务的,有了切面能够保证方法内同一事务了;
解耦通用功能:但是很多方法都需要做事务的控制,有了切面不需要我们每一个方法都加几行相同的代码;
透明化静默操作:方法本身需要知道我怎么开的事务?需要知道我什么时候多打印了日志吗?
PS:我们在此暂不考虑基于XmlApplicationContext系列;怎么实现AOP?
PS:我们在此暂不考虑基于XmlApplicationContext系列;AOP的代码结构与核心概念
大白话:一个模块化的切面程序,也可以理解为是一个实现切面功能的类;
用@Aspect定义的Bean Class,或者Spring xml配置里的aop:aspect标签:
可以理解为要切面的对象类型,比如要加切面的目标是构造器,或者一个方法,或者是一个属性的赋值;Advice
AspectJ中可以有很多种,详见AspectJ Join Points;
SpringAOP中只有一种,就是方法执行(Method execution);
参考:其它
Join Points and Pointcuts
Spring 之AOP AspectJ切入点语法详解
例:
within(com.supalle.springaop..*.UserServiceAopImpl)
execution(* com.supalle.springaop.*.*(..))
within(com.supalle.springaop.TestController) && @annotation(com.supalle.springaop.Log)
XmlApplicationContext的应用需要开启
AnnotationConfigApplicationContext的应用需要开启@EnableAspectJAutoProxy;SpringBoot环境下可以不用,在 org.springframework.boot.autoconfigure.aop.AopAutoConfiguration里已经默认启用;
略Advisor
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors中会查找容器中所有的Advisor类型Bean,也属于AutoProxy的支持;
动态代理是指在程序运行时动态生成代理类的技术,即不需要手工编写代理类的源代码,而是在程序运行期间通过反射等机制动态地生成。Spring AOP
动态代理模式可以帮助我们减少重复的代码,提高代码的可维护性和可扩展性。通常情况下,我们都是通过实现接口来创建代理对象,但是如果一个类没有实现任何接口,我们仍然可以通过动态代理来创建代理对象。动态代理模式适用于一些横切关注点(cross-cutting concerns)的处理,例如日志、安全、事务等功能。
在 Java 中,动态代理模式主要有两种实现方式:
基于 JDK 动态代理(JDK Dynamic Proxy):JDK 提供了一个 java.lang.reflect.Proxy 类,可以动态地创建实现一组给定接口的代理类。要求被代理对象必须实现至少一个接口,并通过 Proxy 类的静态方法 newProxyInstance 来创建代理对象。
基于 CGLIB 动态代理:CGLIB(Code Generation Library) 是一个基于 ASM(Java 字节码操作框架)的高性能字节码生成库,可以在运行时动态生成字节码,并生成对应的代理类。要求被代理对象必须有默认构造函数,并通过 CGLIB 库提供的代理工厂(Enhancer 类)来创建代理对象。
总之,动态代理模式可以帮助我们在程序运行期间动态地生成代理类,从而达到增强功能、添加处理逻辑等目的。
AOT(Ahead-of-time )compiler:预先编译器;Spring AOP的结构与核心类
JIT(Just-In-Time)compiler:即时编译器;
org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
- JdkDynamicAopProxy
- ObjenesisCglibAopProxy
Advice: Action taken by an aspect at a particular join point. Different types of advice include "around", "before", and "after" advice. (Advice types are discussed later.) Many AOP frameworks, including Spring, model an advice as an interceptor and maintain a chain of interceptors around the join point.这句“Many AOP frameworks, including Spring, model an advice as an interceptor and maintain a chain of interceptors around the join point.”翻译过来就是“包括Spring在内的许多AOP框架都将Advice建模为拦截器,并在连接点周围维护拦截器链。”
详见:org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice时序图大致如下:
PS:如果Advisor/Advice是实现了Ordered接口的话,@Order注解是不生效的。
- Spring官方文档:Advice Ordering
- 排序Advisors:org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#sortAdvisors
- 排序同一Aspect中的Advice:org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisorMethods
排序:Ordered=Ordered.HIGHEST_PRECEDENCE; // Integer.MIN_VALUE ;方法内写死,继承才可以修改Spring异步执行的AOP支持。
注意:AsyncAnnotationAdvisor是在AsyncAnnotationBeanPostProcessor后置处理器中创建和匹配,beforeExistingAdvisors=true;排序在所有已经存在的Advisor前。
排序:Ordered=Ordered.HIGHEST_PRECEDENCE; // 继承自父类AsyncExecutionInterceptorSpring注解@Async异步执行的AOP支持。
排序:Ordered=Ordered.LOWEST_PRECEDENCE; // 继承自父类AbstractPointcutAdvisor,可set;Spring注解@Retryable方法失败重试的AOP支持。
注意:RetryConfiguration实现IntroductionAdvisor,排序优先于同order的未实现IntroductionAdvisor的Advisor。
排序:Ordered=Ordered.LOWEST_PRECEDENCE; // 继承自父类AbstractPointcutAdvisor,可set,Spring注解缓存@EnableCaching、@Cacheable等的AOP支持。
默认来自@EnableCaching的order属性,也是LOWEST_PRECEDENCE,可以直接在注解里修改。
排序:Ordered=Ordered.LOWEST_PRECEDENCE; // 继承自父类AbstractPointcutAdvisor,可set,Spring注解事务@Transactional的AOP支持。
默认来自@EnableTransactionManagement的order属性,也是LOWEST_PRECEDENCE,可以直接在注解里修改。
详见源码:另外注释一下:postProcessBeforeInstantiation()钩子执行时,Bean已经完成了 创建对象、属性填充、依赖注入、初始化方法的执行;
- org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor#postProcessAfterInitialization
- org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
Customizing Beans by Using a BeanPostProcessorSpring如何防止反复创建AOP代理类
Spring官方提示:
BeanPostProcessor instances and AOP auto-proxying
Classes that implement the BeanPostProcessor interface are special and are treated differently by the container. All BeanPostProcessor instances and beans that they directly reference are instantiated on startup, as part of the special startup phase of the ApplicationContext. Next, all BeanPostProcessor instances are registered in a sorted fashion and applied to all further beans in the container. Because AOP auto-proxying is implemented as a BeanPostProcessor itself, neither BeanPostProcessor instances nor the beans they directly reference are eligible for auto-proxying and, thus, do not have aspects woven into them.
源码详见:org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) | Powered by Discuz! X3.4 |