spring5.3 十四:spring AOP源码分析

AOP源码分析

上一篇分析过spring 通过ProxyFactory来创建代理对象。下面来分析下ProxyFactory的原理

ProxyFactory源码分析

上一篇aop的介绍中有提到这两行代码

ProxyFactory proxyFactory = new ProxyFactory();
BookInterface bookInterface = (BookInterface)proxyFactory.getProxy();

关键是getProxy方法。

public Object getProxy(@Nullable ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}
protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		// 默认为DefaultAopProxyFactory
		return getAopProxyFactory().createAopProxy(this);
	}
//最终调到这个方法 通过该方法判断是通过cglib代理还是jdk代理
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		// 如果ProxyFactory的isOptimize为true,
		// 或者isProxyTargetClass为true,
		// 或者被代理对象没有实现接口,
		// 或者只实现了SpringProxy这个接口
		// 那么则利用Cglib进行动态代理,但如果被代理类是接口,或者被代理类已经是进行过JDK动态代理而生成的代理类了则只能进行JDK动态代理

		// 其他情况都会进行JDK动态代理,比如被代理类实现了除SpringProxy接口之外的其他接口

		if (!NativeDetector.inNativeImage() &&
				(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
			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.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

决定好通过那个方式进行代理后,真正调getProxy()方法由下面两个实现类
在这里插入图片描述
这里通过jdk的动态代理为例子

spring中jdk动态代理源码分析

JdkDynamicAopProxy这个类就是jdk动态代理源码。

@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		// this实现了InvocationHandler
		return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
	}

这个方法就是放回一个代理对象,不做过多分析。jdk动态代理中,执行代理逻辑和目标方法是通过invoke方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;
		// 拿到被代理对象
		TargetSource targetSource = this.advised.targetSource;
		Object target = null;
		try {
			// 如果接口中没有定义equals()方法,那么则直接调用,不走代理
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// 得到代理对象的类型,而不是所实现的接口
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// 也是直接调用Advised接口中的方法,不走代理逻辑
				// 其实就是利用代理对象获取ProxyFactory中的信息
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}
			Object retVal;
			// 如果ProxyFactory的exposeProxy为true,则将代理对象设置到currentProxy这个ThreadLocal中去
			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);
			//获取被代理对象和执行的方法对应的代理逻辑链路
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
			if (chain.isEmpty()) {
				// 如果没有代理逻辑,则直接调用对应方法
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				//把代理逻辑链路 和代理对象 执行的方法 入参 等封装成MethodInvocation对象
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed();
			}
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				retVal = proxy;
			}
			else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
				throw new AopInvocationException(
						"Null return value from advice does not match primitive return type for: " + method);
			}
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

整个方法的大致流程是:过滤掉equal()、hashcode()这两个方法,这两个方法执行不触发代理逻辑。判断代理类型,执行对应代码。各种判断通过后,List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);方法拿到所有的代理逻辑链路。没有代理逻辑执行目标方法。有代理逻辑,把每个代理逻辑加上代理对象,入参等封装成MethodInvocation对象执行invocation.proceed();方法。
这个过程中核心部分有两个getInterceptorsAndDynamicInterceptionAdvice方法拿到所有代理逻辑。proceed()真正去执行代理逻辑。那么接下来分析如何获取所有代理逻辑和如何去执行
如何获取所有代理逻辑
getInterceptorsAndDynamicInterceptionAdvice这个方法最终调到DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice方法

@Override
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
		// 从ProxyFactory中拿到所设置的Advice(添加时被封装成了DefaultPointcutAdvisor)
		// 添加的时候会控制顺序
		Advisor[] advisors = config.getAdvisors();
		List<Object> interceptorList = new ArrayList<>(advisors.length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		Boolean hasIntroductions = null;

		for (Advisor advisor : advisors) {
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				// 先匹配类
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {

					// 再匹配方法
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					boolean match;
					if (mm instanceof IntroductionAwareMethodMatcher) {
						if (hasIntroductions == null) {
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
						}
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					}
					else {
						match = mm.matches(method, actualClass);
					}

					// 如果匹配则将Advisor封装成为Interceptor
					if (match) {
						//该方法使用了适配器模式,根据配置的切面逻辑类型 BeforeAdvice 、AroundAdvice等等 封装成Interceptor
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else {
				// 将Advisor封装成为Interceptor
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}

这个过程大致是:从ProxyFactory 拿到所有代理逻辑,不管在ProxyFactory 中配置的是addAdvice()还是addAdvisor()都会封装成Advisor。遍历所有代理逻辑,判断该代理逻辑是满足切点(源码中先判断 是否满足被代理的类 ,再判断是否满足被代理的方法)。匹配通过会把所有通过的代理逻辑封装成Interceptor。
如何调用
找到那些代理逻辑需要被调用后。通过invocation.proceed();进行调用

public Object proceed() throws Throwable {
		// currentInterceptorIndex初始值为-1,每调用一个interceptor就会加1
		// 当调用完了最后一个interceptor后就会执行被代理方法
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}
		//都拿到对应的代理逻辑
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		// 当前interceptor是InterceptorAndDynamicMethodMatcher,则先进行匹配,匹配成功后再调用该interceptor
		// 如果没有匹配则递归调用proceed()方法,调用下一个interceptor
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				return proceed();
			}
		}
		else {
			// 直接调用MethodInterceptor,传入this,在内部会再次调用proceed()方法进行递归
			// 比如MethodBeforeAdviceInterceptor
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

整个流程大概是:判断当前执行完的代理逻辑是不是最后一个,如果是执行代理方法。如果不是执行代理逻辑,执行代理逻辑之前会进行类型判断。类型判断未通过递归执行invoke方法,接着判断下一个代理逻辑。判断通过后还有进行方法入参的判断。判断通过执行对应的代理逻辑。

上面这些过程都是ProxyFactory的过程。那么在spring中的Aop流程是怎么使用这个ProxyFactory的呢

springAOP流程源码分析

下面通过spring源码分析上一篇中使用到AOP代码。

@EnableAspectJAutoProxy
@Configuration
public class AopConfig {}
@Component
@Aspect
public class MyAspect {
	@Before("execution(public void aop.BookService.book())")
	public void myBefore(JoinPoint joinPoint) {
		System.out.println("myBefore --- BookService init");
	}
}

其中@EnableAspectJAutoProxy的代码

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;

    boolean exposeProxy() default false;
}

主要是引入了AspectJAutoProxyRegistrar.class。这个类呢主要就给spring容器中注册AnnotationAwareAspectJAutoProxyCreator这个类。并且根据@EnableAspectJAutoProxy的属性值给这个类对应的属性赋值。
在这里插入图片描述
根据类关系图可以看出AnnotationAwareAspectJAutoProxyCreator实际上是一个BeanPostProcessor。注册这个AnnotationAwareAspectJAutoProxyCreator实际上就是注册了一个BeanPostProcessor。在spring生命周期中分析过 。BeanPostProcessor在初始化后执行会执行postProcessAfterInitialization方法。在这里执行的是AbstractAutoProxyCreator.postProcessAfterInitialization方法。

	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				//核心方法 基于当前bean创建代理对象
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {

		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			//这个bean已经是代理类 直接返回
			return bean;
		}
		//advisedBeans表示已经判断过的bean 和下面一个if有关
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			//已经判断过的bean 不需要代理 直接返回
			return bean;
		}
		//isInfrastructureClass(bean.getClass()) 符合这些(Pointcut.class 、Advisor.class 、Advisor.class等)类型的bean不需要aop
		// 当前正在创建的Bean不用进行AOP,比如切面Bean
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		// 判断当前bean是否存在匹配的advice,如果存在则要生成一个代理对象
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			// advisedBeans记录了某个Bean已经进行过AOP了
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

wrapIfNecessary这个过程就是:通过一些条件判断哪些类需要AOP,哪些类不需要AOP。如果需要AOP,核心部分有两个

  • Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);获取所有匹配的切面‘’
  • Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));创建代理对象

先来看创建代理对象

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {
		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (proxyFactory.isProxyTargetClass()) {
			// Explicit handling of JDK proxy targets (for introduction advice scenarios)
			if (Proxy.isProxyClass(beanClass)) {
				// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
				for (Class<?> ifc : beanClass.getInterfaces()) {
					proxyFactory.addInterface(ifc);
				}
			}
		}
		else {
			// No proxyTargetClass flag enforced, let's apply our default checks...
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		// 如果使用了@DeclareParents,那么在添加advisor时,会把对应的接口添加到ProxyFactory中
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		// Use original ClassLoader if bean class not locally loaded in overriding class loader
		ClassLoader classLoader = getProxyClassLoader();
		if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
			classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
		}
		return proxyFactory.getProxy(classLoader);
	}

底层就是通过ProxyFactory来创建代理对象。这也是为什么有先铺垫ProxyFactory的原因。这里就不在分析了。

接下来看如何获取切面
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
		// 寻找匹配的Advisor
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		// 找到所有的Advisor
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		// 进行筛选
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		//子类扩展 可以忽略
		extendAdvisors(eligibleAdvisors);

		// 对Advisor进行排序,按Ordered接口、@Order注解进行排序
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

从上面源码来看 如何获取切面 大致分为三个步骤,

  • 第一步 找到所有的切面 findCandidateAdvisors();
  • 第二步进行筛选 indAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  • 第三步排序 sortAdvisors(eligibleAdvisors);

findCandidateAdvisors()

@Override
	protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
		// 先找到所有Advisor类型的Bean对象
		List<Advisor> advisors = super.findCandidateAdvisors();

		// Build Advisors for all AspectJ aspects in the bean factory.
		// 再从所有切面中解析得到Advisor对象 就是解析@Aspect注解的类下面的@Before等注解
		if (this.aspectJAdvisorsBuilder != null) {
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

这一个步流程就是从spring容器中找出所有的bean判断哪些bean是Advisor类型。通过判断哪些Advisor类型的bean有@Aspect注解,解析@Aspect注解的bean里面的@Before等注解

indAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
该方法底层核心筛选代码就是canApply,通过该方法返回boolean值判断符不符合要求

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		// 判断targetClass是不是和当前Pointcut匹配

		// 先判断类
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}

		MethodMatcher methodMatcher = pc.getMethodMatcher();
		if (methodMatcher == MethodMatcher.TRUE) {
			// No need to iterate the methods if we're matching any method anyway...
			return true;
		}

		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}

		Set<Class<?>> classes = new LinkedHashSet<>();
		if (!Proxy.isProxyClass(targetClass)) {
			classes.add(ClassUtils.getUserClass(targetClass));
		}
		classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

		for (Class<?> clazz : classes) {
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
			for (Method method : methods) {
				if (introductionAwareMethodMatcher != null ?
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
						// 在判断方法是否匹配
						methodMatcher.matches(method, targetClass)) {
					return true;
				}
			}
		}

		return false;
	}

主要也是从类 和方法这两方面进行判断。不在深入分析。

最后进行切面的排序,根据@order注解进行排序也不深入分析。到此SpringAOP流程就结束了
Spring中AOP原理流程图:https://www.processon.com/view/link/5faa4ccce0b34d7a1aa2a9a5
下面来总结一下

总结

  1. 当使用@Aspect进行切面配置的时候需要添加@EnableAspectJAutoProxy表示启动@Aspect的切面配置。原理就是引入了AspectJAutoProxyRegistrar.class
  2. AspectJAutoProxyRegistrar.class向Spring容器中注册了AnnotationAwareAspectJAutoProxyCreator。其父类是BeanPostProcessor类型。在bean的生命周期中的初始化后阶段会执行postProcessAfterInitialization方法。对应上的实现就是AbstractAutoProxyCreator.postProcessAfterInitialization方法。
  3. AbstractAutoProxyCreator.postProcessAfterInitialization方法作用就是判断当前类需要不需要AOP,如果需要返回代理对象,如果不需要返回原始bean对象。其核心方法是wrapIfNecessary
  4. wrapIfNecessary核心步骤有两个 一个找出所有匹配这个bean的切面,另一个是生成代理对象
  5. 找出所有匹配这个bean的切面分为三个步骤 1:找出所有的切面 2:筛选切面 3:切面排序
  6. 当找到匹配的切面后,通过ProxyFactory创建代理对象。到此bean的代理对象就创建完毕
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值