spring (三) AOP源码

spring aop是spring框架的一大核心,用过spring的人应该对于这个内容不会感到陌生。但是,肯定会有人对于spring aop和aspectJ以及proxy和CGLIB比较混乱。

动态代理java里面最常用的一般就是jdk的proxy接口代理,以及CGLIB的继承代理,而spring aop是基于这两种代理的一种封装,具体哪种代理可以根据配置选择,而aspectJ是一个第三方的代理框架,本身和spring毫无关系,但是由于可能是spring自觉得aspectJ语法比较人性化,所以spring将aspectJ中的一些语法做法整合到了spring aop中,注意并不是直接把aspectJ给整合进来了。

所以spring中经常说的@Aspectj的支持,不是指的是和aspectJ整合,而是spring aop自身的一套aspectJ语法,而我们为啥使用注解需要导入aspectJ的包,那是因为spring aop实现aspectJ语法用的注解都是aspectJ包里面的。

当然spring也确确实实整合了aspectJ,不过这个怎么用的就是另外一回事了。

好了,正式开始梳理源码,这里就从@Aspectj注解的实现开头。

spring需要支持@AspectJ,需要添加@EnableAspectJAutoProxy注解,现在的spring boot不需要这个注解是因为spring boot通过条件注解来初始化的。EnableAspectJAutoProxy注解是一个import注解,里面内置了一个@import,导入的类是AspectJAutoProxyRegistrar,这个类是一个实现了ImportBeanDefinitionRegistrar接口的import类,所以就得看这个类registerBeanDefinitions注册了什么

看下面两段代码,可以看到,这里会注册一个AnnotationAwareAspectJAutoProxyCreator类的BeanDefinition 返回,所以,这个AnnotationAwareAspectJAutoProxyCreator类很明显是重中之重。

	@Nullable
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}


   @Nullable
	private static BeanDefinition registerOrEscalateApcAsRequired(
			Class cls, BeanDefinitionRegistry registry, @Nullable Object source) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}

		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

那么就先看一看AnnotationAwareAspectJAutoProxyCreator的类图,从分析类图开始

spring (三) AOP源码_第1张图片

 AnnotationAwareAspectJAutoProxyCreator类继承图看点有三条,首先最明确的是几个Aware接口,所有的Aware接口都是为了注入一些属性,例如BeanFactoryAware就是为了注入beanFactory。第二点是SmartInstantiationAwareBeanPostProcessor,这个接口继承自InstantiationAwareBeanPostProcessor,再继承自BeanPostProcessor,这三个接口在spring ioc这篇博客中出场率还是很高的,在spring ioc的生命周期中起的作用都非常重要。最后就是中间这条主干,这条主干的类继承基本都是为了实现SmartInstantiationAwareBeanPostProcessor、InstantiationAwareBeanPostProcessor、BeanPostProcessor这三个接口的方法。

因此,再来回顾一下spring ioc关于这三个接口的一些内容。

首先BeanPostProcessor不同于普通的Bean,BeanPostProcessor是在refresh方法的registerBeanPostProcessors中从所有的BeanDefinition中查找出来,注册到BeanFactory中。

再看看执行顺序

1、首先是InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation方法。

执行时间在Bean创建对象之前。

2、如果postProcessBeforeInstantiation有bean返回,那么会直接调用这个接口的postProcessAfterInitialization方法,否则populateBean中被调用,3步骤之后

执行时间在Bean创建对象之前,紧接着1之后执行。

3、SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors方法

执行时间在Bean创建对象之前,可以看出在创建对象中。

4、InstantiationAwareBeanPostProcessor的postProcessProperties方法

执行时间在Bean创建对象之后,设置对象属性值的时候。

5、SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法

执行时间设置对象属性值的时候,和循环依赖有关系,在4步骤中

6、InstantiationAwareBeanPostProcessor的postProcessPropertyValues方法

执行时间在Bean创建对象之后,设置对象属性值的时候,紧接着4之后执行

7、BeanPostProcessor的postProcessBeforeInitialization方法

执行时间在Bean执行各种init之前,在各种setAware之后,因为执行顺序,所以基本所有的Aware都调用完后才会被调用

8、BeanPostProcessor的postProcessAfterInitialization方法

执行时间在Bean执行各种init之后。

另外还有一个SmartInstantiationAwareBeanPostProcessor的predictBeanType方法,用于是否匹配类型这一块捋清楚之后,再来一步一步分析代码。

先看1、InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation方法

在类还没反射生成实例的时候,这里传入了类的类型和bean的名称,做了如下操作

首先或判断当前类是否继承了

Advice、Pointcut、Advisor、AopInfrastructureBean四个接口,

或者是以.ORIGINAL结尾,

最后还调用了子类的方法来判断。

findCandidateAdvisors方法用于找出Bean中所有继承了Advisor接口的类以及@aspect注解的类,并生成Advisor列表 ,Advisor算是切面。

而在这个过程中,这个Bean就会被放入spring容器中了。

	@Override
	protected List findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
		List advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		if (this.aspectJAdvisorsBuilder != null) {
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

buildAspectJAdvisors方法中获取出spring容器中所有的bean的名称,用bean的名称获取类型,再反射查看是否有@Aspect注解

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);
		List 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));
	}
}

有的话进入条件往下执行getAdvisors方法

先获取这个类所有的方法,不包括有@Pointcut注解的方法,依次循环

	for (Method method : getAdvisorMethods(aspectClass)) {
			// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
			// to getAdvisor(...) to represent the "current position" in the declared methods list.
			// However, since Java 7 the "current position" is not valid since the JDK no longer
			// returns declared methods in the order in which they are declared in the source code.
			// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
			// discovered via reflection in order to support reliable advice ordering across JVM launches.
			// Specifically, a value of 0 aligns with the default value used in
			// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
			Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

查看方法上是否有以下这几个注解,有的话,获取注解,获取注解上的表达式,生成InstantiationModelAwarePointcutAdvisorImpl

spring (三) AOP源码_第2张图片

最后判断集合中如果有AspectJPointcutAdvisor继承类,并且名称和bean名称相同的跳过,这里如果是注解@Aspect的明显不会有,肯定不会返回true,但如果存在继承Advisor并返回AspectJPointcutAdvisor的类,所有的类执行shouldSkip就会都返回true。

 

接下来看看有没有自定义的customTargetSourceCreators,如果有的话,这里就会生成代理返回。在这种情况下,会立即执行postProcessAfterInitialization,AbstractAutoProxyCreator实现方法中什么也没做

	@Override
	public Object postProcessBeforeInstantiation(Class beanClass, String beanName) {
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

		// Create proxy here if we have a custom TargetSource.
		// Suppresses unnecessary default instantiation of the target bean:
		// The TargetSource will handle target instances in a custom fashion.
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		return null;
	}

再看3、4、6、7,实现类也什么都没做。

来看5、SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法,这是当有循环依赖 比如 a、b互相依赖,先创建a的话,那么a最后就会调用到这个方法。

@Override
	public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		this.earlyProxyReferences.put(cacheKey, bean);
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

这里先放一下。

看8、postProcessAfterInitialization方法,结合5,这里就很明了了,如果有5,在5中会把已经创建的bean放入到earlyProxyReferences缓存map中,并且调用wrapIfNecessary方法,如果5已经执行过,8就不执行了。

/**
	 * Create a proxy with the configured interceptors if the bean is
	 * identified as one to proxy by the subclass.
	 * @see #getAdvicesAndAdvisorsForBean
	 */
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

所以重点看wrapIfNecessary方法做了什么,方法中会为当前类找出对应的Advisors并进行代理,这里同样也调用了findCandidateAdvisors方法,这个方面上面已经分析过了,会返回一个Advisor的列表

	/**
	 * Find all eligible Advisors for auto-proxying this class.
	 * @param beanClass the clazz to find advisors for
	 * @param beanName the name of the currently proxied bean
	 * @return the empty List, not {@code null},
	 * if there are no pointcuts or interceptors
	 * @see #findCandidateAdvisors
	 * @see #sortAdvisors
	 * @see #extendAdvisors
	 */
	protected List findEligibleAdvisors(Class beanClass, String beanName) {
		List candidateAdvisors = findCandidateAdvisors();
		List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

拿到Advisor的列表之后,再进行筛选匹配,找出当前类能用的Advisor。

/**
	 * Search the given candidate Advisors to find all Advisors that
	 * can apply to the specified bean.
	 * @param candidateAdvisors the candidate Advisors
	 * @param beanClass the target's bean class
	 * @param beanName the target's bean name
	 * @return the List of applicable Advisors
	 * @see ProxyCreationContext#getCurrentProxiedBeanName()
	 */
	protected List findAdvisorsThatCanApply(
			List candidateAdvisors, Class beanClass, String beanName) {

		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}

往下,循环Advisor列表,先找出是否有继承自IntroductionAdvisor(引入增强),调用canApply判断方法。接着再找其他的,并传入参数hasIntroductions ,参数标识当前类有没有能用的IntroductionAdvisor 

	/**
	 * Determine the sublist of the {@code candidateAdvisors} list
	 * that is applicable to the given class.
	 * @param candidateAdvisors the Advisors to evaluate
	 * @param clazz the target class
	 * @return sublist of Advisors that can apply to an object of the given class
	 * (may be the incoming List as-is)
	 */
	public static List findAdvisorsThatCanApply(List candidateAdvisors, Class clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List eligibleAdvisors = new ArrayList<>();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				continue;
			}
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}
	/**
	 * Can the given advisor apply at all on the given class?
	 * 

This is an important test as it can be used to optimize out a advisor for a class. * This version also takes into account introductions (for IntroductionAwareMethodMatchers). * @param advisor the advisor to check * @param targetClass class we're testing * @param hasIntroductions whether or not the advisor chain for this bean includes * any introductions * @return whether the pointcut can apply on any method */ public static boolean canApply(Advisor advisor, Class targetClass, boolean hasIntroductions) { if (advisor instanceof IntroductionAdvisor) { return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); } else if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { // It doesn't have a pointcut so we assume it applies. return true; } }

最后调用切点表达式的match方法,这里有两个match,一个类级别的match,Pointcut继承类都会有getClassFilter和getMethodMatcher两个方法,分别存放了类和方法的匹配类

if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}

一个方法的match

	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;
				}
			}
		}

经过类和方法的过滤,这里就会找出能够使用的Advisor。

找到匹配的Advisor列表之后返回,调用extendAdvisors方法,这个方法向Advisor列表最前面添加了一个DefaultPointcutAdvisor,这个类包含了一个ThreadLocal用来保存MethodInvocation,主要用于AspectJ的aop代理。

接着继续返回然后调用createProxy创建代理类

	/**
	 * Create an AOP proxy for the given bean.
	 * @param beanClass the class of the bean
	 * @param beanName the name of the bean
	 * @param specificInterceptors the set of interceptors that is
	 * specific to this bean (may be empty, but not null)
	 * @param targetSource the TargetSource for the proxy,
	 * already pre-configured to access the bean
	 * @return the AOP proxy for the bean
	 * @see #buildAdvisors
	 */
	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()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

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

		return proxyFactory.getProxy(getProxyClassLoader());
	}

到了这里代码就很简单了,通过配置的proxyTargetClass属性,以及存不存在接口决定使用JDK的动态代理还是CGLIB的代理

/**
	 * Create a new proxy according to the settings in this factory.
	 * 

Can be called repeatedly. Effect will vary if we've added * or removed interfaces. Can add and remove interceptors. *

Uses the given class loader (if necessary for proxy creation). * @param classLoader the class loader to create the proxy with * (or {@code null} for the low-level proxy facility's default) * @return the proxy object */ public Object getProxy(@Nullable ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); }

所以说代理的实现都是spring来实现的,AspectJ只是语法上的支持.

 

你可能感兴趣的:(spring,aop,spring,java)