一、AOP
1. 涉及的相关概念
先回顾下核心的概念,比如:Advice,Pointcut,Aspect等
更加形象的描述:
2. 相关核心的设计
Advice:
Pointcut:
Aspect:
Advisor:
织入:
二、AOP相关概念的类结构
回顾了前面的内容,然后我们来看看Spring中AOP是如何来实现的了。
1. Advice类结构
我们先来看看Advice的类结构,advice--》通知,需要增强的功能
相关的说明
2. Pointcut类结构
然后来看看Pointcut的设计,也就是切入点的处理。
Pointcut的两种实现方式
3. Advisor类结构
Advisor的类结构比较简单。一个是PointcutAdvisor,一个是IntroductionAdvisor
我们要看的重点是 PointcutAdvisor 及实现 AspectJPointcutAdvisor。
三、织入的实现
1. BeanPostProcessor
1.1 案例演示
我们通过案例来看,首先使用AOP来增强。
定义切面类
/** * 切面类 */ @Component @EnableAspectJAutoProxy @Aspect public class AspectAdviceBeanUseAnnotation { // 定义一个全局的Pointcut @Pointcut("execution(* com.study.spring.sample.aop.*.do*(..))") public void doMethods() { } @Pointcut("execution(* com.study.spring.sample.aop.*.service*(..))") public void services() { } // 定义一个Before Advice @Before("doMethods() and args(tk,..)") public void before3(String tk) { System.out.println("----------- AspectAdviceBeanUseAnnotation before3 增强 参数tk= " + tk); } @Around("services() and args(name,..)") public Object around2(ProceedingJoinPoint pjp, String name) throws Throwable { System.out.println("--------- AspectAdviceBeanUseAnnotation arround2 参数 name=" + name); System.out.println("----------- AspectAdviceBeanUseAnnotation arround2 环绕-前增强 for " + pjp); Object ret = pjp.proceed(); System.out.println("----------- AspectAdviceBeanUseAnnotation arround2 环绕-后增强 for " + pjp); return ret; } @AfterReturning(pointcut = "services()", returning = "retValue") public void afterReturning(Object retValue) { System.out.println("----------- AspectAdviceBeanUseAnnotation afterReturning 增强 , 返回值为: " + retValue); } @AfterThrowing(pointcut = "services()", throwing = "e") public void afterThrowing(JoinPoint jp, Exception e) { System.out.println("----------- AspectAdviceBeanUseAnnotation afterThrowing 增强 for " + jp); System.out.println("----------- AspectAdviceBeanUseAnnotation afterThrowing 增强 异常 :" + e); } @After("doMethods()") public void after(JoinPoint jp) { System.out.println("----------- AspectAdviceBeanUseAnnotation after 增强 for " + jp); } /* * BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor * InstantiationAwareBeanPostProcessor Bean实例创建前后 BeanPostProcessor */ } 复制代码
需要增强的目标类
@Component public class BeanQ { public void do1(String task, int time) { System.out.println("-------------do1 do " + task + " time:" + time); } public String service1(String name) { System.out.println("-------------servce1 do " + name); return name; } public String service2(String name) { System.out.println("-------------servce2 do " + name); if (!"s1".equals(name)) { throw new IllegalArgumentException("参数 name != s1, name=" + name); } return name + " hello!"; } } 复制代码
测试代码
@Configuration @ComponentScan public class AopMainAnno { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(AopMainAnno.class); BeanQ bq = context.getBean(BeanQ.class); bq.do1("task1", 20); System.out.println(); bq.service1("service1"); System.out.println(); bq.service2("s1"); } } 复制代码
执行即可看到增强的效果
1.2 @EnableAspectJAutoProxy
我们需要使用代理增强处理,必须添加@EnableAspectJAutoProxy才生效。我们来看看他做了什么事情
在registerOrEscalateApcAsRequired方法中会把上面的Java类注入到容器中。
所以我们需要看看 AnnotationAwareAspectJAutoProxyCreator 的结构
1.3 AnnotationAwareAspectJAutoProxyCreator
我们直接来看类图结构,可以发现其本质就是一个 BeanPostProcessor ,只是扩展了更多的功能。
那么具体处理的逻辑
1.4 如何串联
Bean的IoC是如何和对应的BeanPostProcessor串联的呢?我们来看看。
isInfrastructureClass方法判断是否是基础设施
shouldSkip:是否应该跳过,会完成相关的advisor的收集
具体的处理流程
public List<Advisor> findAdvisorBeans() { // Determine list of advisor bean names, if not cached already. String[] advisorNames = this.cachedAdvisorBeanNames; if (advisorNames == null) { // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the auto-proxy creator apply to them! // 获取当前BeanFactory中所有实现了Advisor接口的bean的名称 advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } if (advisorNames.length == 0) { return new ArrayList<>(); } // 对获取到的实现Advisor接口的bean的名称进行遍历 List<Advisor> advisors = new ArrayList<>(); // 循环所有的beanName,找出对应的增强方法 for (String name : advisorNames) { // isEligibleBean()是提供的一个hook方法,用于子类对Advisor进行过滤,这里默认返回值都是true if (isEligibleBean(name)) { // 如果当前bean还在创建过程中,则略过,其创建完成之后会为其判断是否需要织入切面逻辑 if (this.beanFactory.isCurrentlyInCreation(name)) { if (logger.isTraceEnabled()) { logger.trace("Skipping currently created advisor '" + name + "'"); } } else { try { // 将当前bean添加到结果中 advisors.add(this.beanFactory.getBean(name, Advisor.class)); } catch (BeanCreationException ex) { // 对获取过程中产生的异常进行封装 Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; String bceBeanName = bce.getBeanName(); if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) { if (logger.isTraceEnabled()) { logger.trace("Skipping advisor '" + name + "' with dependency on currently created bean: " + ex.getMessage()); } // Ignore: indicates a reference back to the bean we're trying to advise. // We want to find advisors other than the currently created bean itself. continue; } } throw ex; } } } } return advisors; } 复制代码
2. 代理类的结构
在上面的分析中出现了很多代理相关的代码,为了更好的理解,我们来梳理下Spring中的代理相关的结构
2.1 AopProxy
在Spring中创建代理对象都是通过AopProxy这个接口的两个具体实现类来实现的,也就是jdk和cglib两种方式。
2.2 AopProxyFactory
在Spring中通过AopProxyFactory这个工厂类来提供AopProxy。
默认的实现类是DefaultAopProxyFactory
/** * 真正的创建代理,判断一些列条件,有自定义的接口的就会创建jdk代理,否则就是cglib * @param config the AOP configuration in the form of an * AdvisedSupport object * @return * @throws AopConfigException */ @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // 这段代码用来判断选择哪种创建代理对象的方式 // config.isOptimize() 是否对代理类的生成使用策略优化 其作用是和isProxyTargetClass是一样的 默认为false // config.isProxyTargetClass() 是否使用Cglib的方式创建代理对象 默认为false // hasNoUserSuppliedProxyInterfaces目标类是否有接口存在 且只有一个接口的时候接口类型不是SpringProxy类型 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { // 上面的三个方法有一个为true的话,则进入到这里 // 从AdvisedSupport中获取目标类 类对象 Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } // 判断目标类是否是接口 如果目标类是接口的话,则还是使用JDK的方式生成代理对象 // 如果目标类是Proxy类型 则还是使用JDK的方式生成代理对象 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } // 配置了使用Cglib进行动态代理或者目标类没有接口,那么使用Cglib的方式创建代理对象 return new ObjenesisCglibAopProxy(config); } else { // 使用JDK的提供的代理方式生成代理对象 return new JdkDynamicAopProxy(config); } } 复制代码
2.3 ProxyFactory
ProxyFactory代理对象的工厂类,用来创建代理对象的工厂。
然后我们来看看 ProxyFactory的体系结构
ProxyConfig
这个类主要保存代理的信息,如果是否使用类代理,是否要暴露代理等。
public class ProxyConfig implements Serializable { /** use serialVersionUID from Spring 1.2 for interoperability. */ private static final long serialVersionUID = -8409359707199703185L; // 是否代理的对象是类,动态代理分为代理接口和类,这里的属性默认是代理的接口 private boolean proxyTargetClass = false; // 是否进行主动优化,默认是不会主动优化 private boolean optimize = false; // 是否由此配置创建的代理不能被转成Advised类型,默认时候可转 boolean opaque = false; // 是否会暴露代理在调用的时候,默认是不会暴露 boolean exposeProxy = false; // 是否冻结此配置,不能被修改 private boolean frozen = false; } 复制代码
Advised
由持有 AOP 代理工厂配置的类实现的接口。此配置包括拦截器和其他advice、advisor和代理接口。从 Spring 获得的任何 AOP 代理都可以转换为该接口,以允许操作其 AOP 通知。
AdvisedSupport
- AOP代理配置管理器的基类。 此类的子类通常是工厂,从中可以直接获取 AOP 代理实例。此类可释放Advices和Advisor的内部管理子类,但实际上并没有实现代理创建方法,实现由子类提供
- AdvisedSupport实现了Advised中处理Advisor和Advice的方法,添加Advice时会被包装成一个Advisor,默认使用的Advisor是DefaultPointcutAdvisor,DefaultPointcutAdvisor默认的Pointcut是TruePointcut(转换为一个匹配所有方法调用的Advisor与代理对象绑定)。
- AdvisedSupport同时会缓存对于某一个方法对应的所有Advisor(Map<MethodCacheKey, List<Object>> methodCache),当Advice或Advisor发生变化时,会清空该缓存。getInterceptorsAndDynamicInterceptionAdvice用来获取对应代理方法对应有效的拦截器链 。
ProxyCreatorSupport
继承了AdvisedSupport,ProxyCreatorSupport正是实现代理的创建方法,ProxyCreatorSupport有一个成员变量AopProxyFactory,而该变量的值默认是DefaultAopProxyFactory
这个也就和前面的AopProxyFactory串联起来了。