今天看啥  ›  专栏  ›  hiyouka

SpringAop分析

hiyouka  · 掘金  ·  · 2019-08-23 08:27

文章预览

阅读 45

SpringAop分析

前言

  原来只是想看下Spring事务管理的原理,但在寻找事务起作用的源头时,就把Aop的代码几乎看遍了。。。所以就顺便写了一篇关于Aop原理的文章。希望能帮到大家(^_^)

SpringBoot自动配置

  和看事务管理一样,还是根据SpringBoot配置了哪些关键类来分析原理。可以从Spring.factories找到Spring自动配置类AopAutoConfiguration。该类根据配置文件有没有spring.aop.auto=true(该值默认为true)。该类上添加了@EnableAspectJAutoProxy注解,所以我们可以很清楚的看出,springboot默认是开启aop功能的。而@EnableAspectJAutoProxy向spring容器中添加了自定义配置Aop起作用的关键类AnnotationAwareAspectJAutoProxyCreator

img

Aop原理

代理类的创建

  SpringBoot自动配置给容器加入了Aop的核心类,AnnotationAwareAspectJAutoProxyCreator,该类实现了SmartInstantiationAwareBeanPostProcessor接口,所以在bean的创建前后分别会调用该类的postProcessBeforeInstantiationpostProcessAfterInstantiation方法。
  postProcessBeforeInstantiation方法会获取TargetSource来在对象创建前调用createProxy来创建代理对象。目前还没搞清楚什么情况会有TargetSource。   postProcessAfterInstantiation方法调用wrapIfNecessary方法,先获取所有的切点拦截器,创建的时候与代理类所绑定。具体创建代理类的逻辑实在是没看懂,Spring自己封装了cglib代理类实现,不过也是创建了DynamicAdvisedInterceptor为主拦截器的代理类,还有之前查找的所有切面拦截器。下面源码就是Spirng通过我们配置的切面表示创建Advisor的过程。

public List<Advisor> buildAspectJAdvisors() {
		List<String> aspectNames = this.aspectBeanNames;
		//第一次去获取切面配置类
		if (aspectNames == null) {
			synchronized (this) {
				aspectNames = this.aspectBeanNames;
				if (aspectNames == null) {
					// 获取所有类名 遍历
					for (String beanName : beanNames) {
						Class<?> beanType = this.beanFactory.getType(beanName);
						// 如果该类有@Aspect注解,并且不是AspectJ类
						//We need to detect this as "code-style" AspectJ aspects should not be interpreted by Spring AOP.
						if (this.advisorFactory.isAspect(beanType)) {
							aspectNames.add(beanName);
							AspectMetadata amd = new AspectMetadata(beanType, beanName);
							if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
								MetadataAwareAspectInstanceFactory factory =
										new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
								//创建对方法进行增强处理的Advisor(InstantiationModelAwarePointcutAdvisorImpl)
								//该增强器默认有AspectJExpressionPointcut作为你匹配,之后进行matches是会使用
								List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
								if (this.beanFactory.isSingleton(beanName)) {
									this.advisorsCache.put(beanName, classAdvisors);
								}
								else {
									this.aspectFactoryCache.put(beanName, factory);
								}
								advisors.addAll(classAdvisors);
							}
							else {
								// Per target or per this.
								if (this.beanFactory.isSingleton(beanName)) {
									throw new IllegalArgumentException("Bean with name '" + beanName +
											"' is a singleton, but aspect instantiation model is not singleton");
								}
								MetadataAwareAspectInstanceFactory factory =
										new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
								this.aspectFactoryCache.put(beanName, factory);
								advisors.addAll(this.advisorFactory.getAdvisors(factory));
							}
						}
					}
					this.aspectBeanNames = aspectNames;
					return advisors;
				}
			}
		}
		return advisors;
	}
复制代码

img
  DynamicAdvisedInterceptor类是Aop每个代理类都有的拦截器,当调用代理类的方法时,首先会调用该类的intercept方法。


@Override
   @Nullable
   public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
   	Object oldProxy = null;
   	boolean setProxyContext = false;
   	Object target = null;
   	TargetSource targetSource = this.advised.getTargetSource();
   	try {
   	    // 对aop暴露进行处理,如果暴露则将代理类置入当前线程中,之后嵌套调用可以取到
   		if (this.advised.exposeProxy) {
   			// Make invocation available if necessary.
   			oldProxy = AopContext.setCurrentProxy(proxy);
   			setProxyContext = true;
   		}
   		// 获取原始对象(代理前对象)
   		target = targetSource.getTarget();
   		Class<?> targetClass = (target != null ? target.getClass() : null);
   		// 获取拦截器链,就是在创建代理类前获取的拦截处理器,对方法进行匹配,和之前讲的事务Advisor一样
   		// 通过MethodMatcher来匹配,这边是AspectJExpressionPointcut的mathces对表达式进行解析
   		// 自定义的切面是通过之前的Advisor来生成的拦截器
   		// MethodBeforeAdviceAdapter AfterReturningAdviceAdapter ThrowsAdviceAdapter
   		//通过是否匹配上面三种adapter分别生成 
   		//MethodBeforeAdviceInterceptor AfterReturningAdviceInterceptor ThrowsAdviceInterceptor
   		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
   		Object retVal;
   		if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
   		    // 没有增强处理器直接执行原始对象的方法
   			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
   			retVal = methodProxy.invoke(target, argsToUse);
   		}
   		else {
   			//调用CglibMethodInvocation.process(),
   			//该方法会递归执行所有拦截器链中的方法,知道调用完成原始方法
   			retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
   		}
   		// 对返回结果进行处理
   		retVal = processReturnType(proxy, target, method, retVal);
   		return retVal;
   	}
   	finally {
   		if (target != null && !targetSource.isStatic()) {
   			targetSource.releaseTarget(target);
   		}
   		if (setProxyContext) {
   			// Restore old proxy.
   			AopContext.setCurrentProxy(oldProxy);
   		}
   	}
   }

复制代码

其他Spring切面

  @EnableAsync可以开启Spring管理的线程池,利用注解方式简单实现方法多线程调用。但是有一点需要注意(我觉得是Spring的bug),该注解实现还是利用的Aop,但是使用另一个Bean后置处理器:AsyncAnnotationBeanPostProcessor,从下面代码可以看出,在bean创建完成后会对未代理过的类创建代理对象,如果已经是代理类则添加一个切面处理器进去。由于在新创建代理类的时候使用的是独立的后置处理器,所以在切面设置的一些属性对@Async无效(例如expose暴露)。所以如果想让只有@Async注解的代理类,想要使暴露生效只能额外对该后置处理器添加属性。

@Override
   public Object postProcessAfterInitialization(Object bean, String beanName) {
   	if (this.advisor == null || bean instanceof AopInfrastructureBean) {
   		// Ignore AOP infrastructure such as scoped proxies.
   		return bean;
   	}
       
       // 如果该bean已经被处理过(代理类)
   	if (bean instanceof Advised) {
   		Advised advised = (Advised) bean;
   		// 如果需要被处理(有@Async注解)
   		if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
   			// Add our local Advisor to the existing proxy's Advisor chain...
   			if (this.beforeExistingAdvisors) {
   				advised.addAdvisor(0, this.advisor);
   			}
   			else {
   				advised.addAdvisor(this.advisor);
   			}
   			return bean;
   		}
   	}

       // 如果需要被处理(有@Async注解)
   	if (isEligible(bean, beanName)) {
   		ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
   		if (!proxyFactory.isProxyTargetClass()) {
   			evaluateProxyInterfaces(bean.getClass(), proxyFactory);
   		}
   		proxyFactory.addAdvisor(this.advisor);
   		customizeProxyFactory(proxyFactory);
   		return proxyFactory.getProxy(getProxyClassLoader());
   	}

   	// No proxy needed.
   	return bean;
   }
复制代码

总结:

  Spring通过为元类创建代理类添加DynamicAdvisedInterceptor的拦截器来实现拦截器链,通过拦截器链我们自己创建的切面添加到拦截器链当中(可以自定义顺序),这样非常灵活方便的为我们提供了对类方法扩展的功能。另外推荐一篇对AOP扩展的文章,写的很好。觉得本文对你有帮助的小伙伴不妨点个赞,你们的关注是我继续下去的动力。

………………………………

原文地址:访问原文地址
快照地址: 访问文章快照
总结与预览地址:访问总结与预览