005-Spring AOP

146 阅读6分钟

小思:

  • 实例化前和实例化后的区别在于有无推断出构造方法,有构造方法才能实例化。
  • Bean的实例化和初始化区别是否填充了属性,填充了属性是初始化后。
  • Bean的aop动态代理创建时在初始化之后,但是,如果循环依赖的Bean使用了aop. 需要提前创建aop在实例化后初始化前。

介绍下AspectJ和AOP和关系 ?

AOP是什么技术?

AOP把系统分解为不同的关注点,或者称之为切面(Aspect)-是在我们原来写的代码上进行一定的包装,在方法执行前后进行一些拦截处理或者增强处理、减少重复代码。 我们要实现一个代理,实际运行的实例其实是生成的代理类的实例。

Spring中的AOP?(和AspectJ进行对比)

  • Spring 2.0 @AspectJ 配置:使用注解的方式来配置,这种方式感觉是最方便的,还有,这里虽然叫 做 @AspectJ,但是这个和 AspectJ 其实没啥关系。
  • ring AOP 只能作用于 Spring 容器中的 Bean,它是使用纯粹的 Java 代码实现的,只能作用于 bean 的方 法。
  • Spring AOP 需要依赖于 IOC 容器来管理。
  • Spring 提供了 AspectJ 的支持,但只用到的AspectJ的切点解析和匹配。
  • Spring AOP 是基于代理实现的,在容器启动的时候需要生成 代理实例,在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ 那么好。
  • spring源码中只是使用了aspectjrt-1.9.5.jar中的中的注解,但是不依赖于其实现功能。

AspectJ是什么?

  • Compile-time weaving:编译期织入,如类 A 使用 AspectJ 添加了一个属性,类 B 引 用了它,这个场景就需要编译期的时候就进行织入,否则没法编译类 B。
  • Post-compile weaving:编译后加载类前织入,也就是已经生成了 .class 文件,或已经打成 jar 包 了,这种情况我们需要增强处理的话,就要用到编译后织入。
  • Load-time weaving:指的是在加载类的时候进行织入,要实现这个时期的织入,有几 种常见的方法。
    1. 自定义类加载器来干这个,这个应该是最容易想到的办法,在被织入类加 载到 JVM 前去对它进行加载,这样就可以在加载的时候定义行为了。
    2. 在 JVM 启动的时候 指定 AspectJ 提供的 agent:-javaagent:xxx/xxx/aspectjweaver.jar。解答Spring AOP 比 AspectJ慢)因为 AspectJ 在实际代码运行前完成了织入,所以大家会说它生成的类是没有额外运行时开销的。

Advisor 和 Advice

Advice:建议,通知(Spring)。

  1. 前置Advice:MethodBeforeAdvice
  2. 后置Advice:AfterReturningAdvice
  3. 环绕Advice:MethodInterceptor
  4. 异常Advice:ThrowsAdvice

使用Spring AOP去生成一个代理对象时,我们可以设置这个代理对象的Advice。它只表示了“建议”,它没有表示这个“建议”可以用在哪些方面。 Advisor(统帅者),表示一个Advice(worker)可以应用在哪些地方,而“哪些地方”就是Pointcut(切点)。

spring aop源码解析-思考思路

  1. 找到所有的切面类
  2. 解析出所有的advice并保存
  3. 创建一个动态代理类
  4. 调用被代理类的方法时,找到他的所有增强器,并增强当前的方法

一、进入解析切面的过程:

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {}
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);

追踪一下源码可以看到最终到AnnotationAwareAspectJAutoProxyCreator,我们看一下他的类继承关系图,发现它实现了两个重要 的接口,BeanPostProcessor和InstantiationAwareBeanPostProcessor。

首先看InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法 -> Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)(InstantiationAwareBeanPostProcessor)


org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation


org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip


org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors


org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors


//1.找到切面类的所有但是不包括@Pointcut注解的方法 //2.筛选出来包含@Around, @Before, @After,@AfterReturning, @AfterThrowing注解的方法 //3.封装为List返回 List classAdvisors = this.advisorFactory.getAdvisors(factory);


//当再次进入该方法,会直接从advisorsCache缓存中获取 List cachedAdvisors = this.advisorsCache.get(aspectName);

二、创建代理 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean exposedObject = initializeBean(beanName, exposedObject, mbd);


// 4.4、初始化后 AOP

wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);


Object current = processor.postProcessAfterInitialization(result, beanName);


1.获取advisors:

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
			if (bean != null) {
				Object cacheKey = getCacheKey(bean.getClass(), beanName);
				// earlyProxyReferences中存的是哪些提前进行了AOP的bean,beanName:AOP之前的对象
				// 注意earlyProxyReferences中并没有存AOP之后的代理对象  BeanPostProcessor
				if (this.earlyProxyReferences.remove(cacheKey) != bean) {
					// 没有提前进行过AOP,则进行AOP
					return wrapIfNecessary(bean, beanName, cacheKey);
				}
			}
			// 为什么不返回代理对象呢?
			return bean;   //
		}
wrapIfNecessary(bean, beanName, cacheKey);

// 获取当前beanClass所匹配的advisors

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
2.匹配:根据advisors和当前的bean根据切点表达式进行匹配,看是否符合。
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Advisor, java.lang.Class<?>, boolean) 拿到PointCut org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean) org.springframework.aop.ClassFilter#matches 粗筛 org.springframework.aop.IntroductionAwareMethodMatcher#matches 精筛

3.创建代理:找到了 和当前Bean匹配的advisor说明满足创建动态代理的条件:

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// 存一个代理对象的类型
this.proxyTypes.put(cacheKey, proxy.getClass());

// 是否指定了必须用cglib进行代理
		if (!proxyFactory.isProxyTargetClass()) {
			// 如果没有指定,那么则判断是不是应该进行cglib代理(判断BeanDefinition中是否指定了要用cglib)
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			} else {
				// 是否进行jdk动态代理,如果当前beanClass实现了某个接口,那么则会使用JDK动态代理
				evaluateProxyInterfaces(beanClass, proxyFactory); // 判断beanClass有没有实现接口
			}
		}

JdkDynamicAopProxy创建代理对象过程

  1. 获取生成代理对象所需要实现的接口集合 a. 获取通过ProxyFactory.addInterface()所添加的接口,如果没有通过ProxyFactory.addInterface()添加接口,那么则看ProxyFactory.setTargetClass()所设置的targetClass是不是一个接口,把接口添加到结果集合中 b. 同时把SpringProxy、Advised、DecoratingProxy这几个接口也添加到结果集合中去
  2. 确定好要代理的集合之后,就利用Proxy.newProxyInstance()生成一个代理对象

三、代理类的调用JdkDynamicAopProxy创建的代理对象执行过程

  1. 如果通过ProxyFactory.setExposeProxy()把exposeProxy设置为了true,那么则把代理对象设置到一个ThreadLocal(currentProxy)中去。
  2. 获取通过ProxyFactory所设置的target,如果设置的是targetClass,那么target将为null
  3. 根据当前所调用的方法对象寻找ProxyFactory中所添加的并匹配的Advisor,并且把Advisor封装为MethodInterceptor返回,得到MethodInterceptor链叫做chain
  4. 如果chain为空,则直接执行target对应的当前方法,如果target为null会报错
  5. 如果chain不为空,则会依次执行chain中的MethodInterceptor a. 如果当前MethodInterceptor是MethodBeforeAdviceInterceptor,那么则先执行Advisor中所advice的before()方法,然后执行下一个MethodInterceptor b. 如果当前MethodInterceptor是AfterReturningAdviceInterceptor,那么则先执行下一个MethodInterceptor,拿到返回值之后,再执行Advisor中所advice的afterReturning()方法 ObjenesisCglibAopProxy创建代理对象过程
  6. 创建Enhancer
  7. 设置Enhancer的superClass为通过ProxyFactory.setTarget()所设置的对象的类
  8. 设置Enhancer的interfaces为通过ProxyFactory.addInterface()所添加的接口,以及SpringProxy、Advised接口
  9. 设置Enhancer的Callbacks为DynamicAdvisedInterceptor
  10. 最后通过Enhancer创建一个代理对象 ObjenesisCglibAopProxy创建的代理对象执行过程
  11. 执行过程主要就看DynamicAdvisedInterceptor中的实现,执行逻辑和JdkDynamicAopProxy中是一样的。