Spring AOP编程官方文档解读之AP篇


Spring AOP编程官方文档解读目录



前言

在前面几章,我们从原始Java API来介绍了AOP中涉及到的各个部分:AdvicePointcutAdvisor,通过ProxyFactoryBeanProxyFactory来创建代理, 可是,仅仅这样还不能让Spring成为一个强大的框架。因为如果需要我们一个一个代理的创建,那将是非常麻烦的事情。因为Spring除了AW(autowired)之外,还有一个AP的概念。那么什么是AP呢?auto-proxy,自动代理。其实在一开始的篇章当中,我们就开始这种编程了,@EnableAspectJAutoProxy这个注解就是用来开启自动代理的。那么这个注解究竟是如何作用的?自动代理的原理是怎样的呢?通过前面几章的铺垫,我们离自动代理只差临门一脚了。


提示:以下是本篇文章正文内容,下面案例可供参考

一、与AP相关的Bean定义

org.springframework.aop.framework.autoproxy包中提供了以下标准的自动代理的创建器。

1. BeanNameAutoProxyCreator

两个主要的参数,

  • beanNames:用于定义需要进行代理的bean的名称,支持通配符*,支持多个值
    比如*Service指定所有bean名称以Service结尾的都需要进行代理。
  • interceptorNames:与ProxyFactoryBean中用法一直,可以是InterceptorAdviceAdvisor.
package com.example.aop.advice;

import com.example.aop.advice.service.DemoService;
import com.example.aop.advice.service.OrderService;
import com.example.aop.advice.service.impl.DemoServiceImpl;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class RootConfig {

    @Bean
    public SimpleBeforeAdvice simpleBeforeAdvice() {
        return new SimpleBeforeAdvice();
    }

    @Bean
    public SimpleMethodInteceptor simpleMethodInteceptor() {
        return new SimpleMethodInteceptor();
    }

    @Bean
    public DemoService demoService() {
        return new DemoServiceImpl();
    }

    @Bean
    public OrderService orderService() {
        return new OrderService();
    }

    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
        BeanNameAutoProxyCreator autoProxyCreator = new BeanNameAutoProxyCreator();
        autoProxyCreator.setBeanNames("*Service");
        autoProxyCreator.setInterceptorNames("simpleBeforeAdvice", "simpleMethodInteceptor");
        return autoProxyCreator;
    }
}

以上通过beanNameAutoProxyCreator为所有名称以Service的Bean创建了代理。

2. DefaultAdvisorAutoProxyCreator

一个更通用,功能更强大的自动代理创建器是DefaultAdvisorAutoProxyCreator。 这将自动在当前上下文中应用合格的Advisor,而无需在自动代理Advisor的Bean定义中包括特定的Bean名称。 它具有与BeanNameAutoProxyCreator相同的一致配置(consistent configuration)和避免重复(avoidance of duplication)的优点。

使用此机制涉及:

  • 指定DefaultAdvisorAutoProxyCreatorBean定义。
  • 在相同或相关的上下文中指定任意数量的Advisor类型的Bean。 请注意,这些必须是Advisor,而不仅仅是interceptor或其他Advice。 这是必要的,因为必须有一个用于匹配的pointcut,以检查每个Advice是否符合候选bean定义。

DefaultAdvisorAutoProxyCreator将自动评估每个Advisor中包含的切入点,以查看是否应将其应用于每个业务对象上。比如demoService、orderService。

这意味着可以将任意数量的Advisor自动应用于每个业务对象。 如果任何Advisor中的切入点(pointcut)都不匹配业务对象中的任何方法,则该对象将不会被代理。 当为新的业务对象添加bean定义时,如有必要,它们将自动被代理。

比如

package com.example.aop.advice;

import com.example.aop.advice.service.DemoService;
import com.example.aop.advice.service.OrderService;
import com.example.aop.advice.service.impl.DemoServiceImpl;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;

@Configuration
public class RootConfig {


    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        return new DefaultAdvisorAutoProxyCreator();
    }

    @Bean
    public StaticMethodMatcherPointcutAdvisor beforeAdvisor() {
        SimpleBeforeAdvice simpleBeforeAdvice = new SimpleBeforeAdvice();
        return new StaticMethodMatcherPointcutAdvisor(simpleBeforeAdvice) {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                return method.getName().startsWith("find");
            }
        };
    }

    @Bean
    public StaticMethodMatcherPointcutAdvisor aroundAdvisor() {
        SimpleMethodInteceptor simpleMethodInteceptor = new SimpleMethodInteceptor();
        return new StaticMethodMatcherPointcutAdvisor(simpleMethodInteceptor) {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                return method.getName().startsWith("update");
            }
        };
    }

    @Bean
    public DemoService demoService() {
        return new DemoServiceImpl();
    }

    @Bean
    public OrderService orderService() {
        return new OrderService();
    }
}

比如在上面beforeAdvisor针对所有以find开头的方法进行增强、aroundAdvisor针对所有以update开头的方法进行增强。然后在容器中注册一个DefaultAdvisorAutoProxyCreator类型的bean.然后对应的bean就会被增强了。

通常,自动代理的优点是使调用者或依赖者无法获得为被代理的对象。 在此ApplicationContext上调用getBean(DemoService.class)将返回一个AOP代理,而不是目标业务对象。

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
DemoService demoService = applicationContext.getBean(DemoService.class);
demoService.findById(9527L);
User james = new User(9526L, "james", 20);

System.out.println("*************************************");

UserService userService = applicationContext.getBean(UserService.class);
userService.update(james);
applicationContext.close();

运行结果如下

九月 27, 2020 12:12:36 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5197848c: startup date [Sun Sep 27 12:12:36 CST 2020]; root of context hierarchy
九月 27, 2020 12:12:37 下午 org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker postProcessAfterInitialization
信息: Bean 'rootConfig' of type [com.example.aop.advice.RootConfig$$EnhancerBySpringCGLIB$$f4249d33] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
-----SimpleBeforeAdvice-----😄😄findById增强-------------
----findById----User{userId=9527, name='周星星', age=18}
*************************************
----SimpleMethodInteceptor--before proceed----update增强-------------
---UserService-add user----User{userId=9526, name='james', age=20}
----SimpleMethodInteceptor--after proceed----update增强-------------
九月 27, 2020 12:12:37 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@5197848c: startup date [Sun Sep 27 12:12:36 CST 2020]; root of context hierarchy

如果要将相同的Advisor一致地应用于许多业务对象,则DefaultAdvisorAutoProxyCreator非常有用。 基础结构定义到位后,您可以简单地添加新的业务对象,而无需包括特定的代理配置。 您还可以非常轻松地加入其他Aspect,例如跟踪或性能监视方面,而对配置的更改最少。

DefaultAdvisorAutoProxyCreator提供过滤支持(使用命名约定,以便仅评估某些Advisor,从而允许在同一工厂中使用多个配置不同的AdvisorAutoProxyCreators)和排序。 Advisor可以实现org.springframework.core.Ordered接口,以确保在出现问题时可以正确排序。

1. 过滤支持

比如设置只关注beanName以before开头的Advisor.

@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
    defaultAdvisorAutoProxyCreator.setUsePrefix(true);
    defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("before");
    return defaultAdvisorAutoProxyCreator;
}

2. 排序支持

对应源码
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
首先查找所有候选Advisor,然后则筛选出合格Advisor,最后进行排序

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
	// 查找候选者
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	// 查找合格者
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	extendAdvisors(eligibleAdvisors);
	if (!eligibleAdvisors.isEmpty()) {
	    // 进行排序
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
	}
	return eligibleAdvisors;
}

protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
	AnnotationAwareOrderComparator.sort(advisors);
	return advisors;
}

有几点需要注意

  1. 在配置类中使用@Order注解是无效的,必须放在对应类上面。如下案例是无效的
@Order(10)
@Bean
public SimpleAdvisor simpleAdvisor() {
    return new SimpleAdvisor();
}

如下案例是有效的

@Order(10)
public class SimpleAdvisor implements PointcutAdvisor {

  1. 如果继承Spring提供的抽象类需要注意是否已经实现了org.springframework.core.Ordered接口,比如org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor实现了这个接口,而且对应的order值非常大,基本排序再最后。
private int order = Integer.MAX_VALUE;

这个时候无论是在bean定义上面还是类上面添加@Order注解是无效的。此时可以覆盖对应的getOrder方法即可

package com.example.aop.advisor;

import org.aopalliance.aop.Advice;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;

import java.lang.reflect.Method;

public class AroundAdvisor extends StaticMethodMatcherPointcutAdvisor {

    public AroundAdvisor(Advice advice) {
        super(advice);
    }

    @Override
    public int getOrder() {
        return -15;
    }

    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return method.getName().startsWith("update");
    }
}
package com.example.aop.advisor;

import org.aopalliance.aop.Advice;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;

import java.lang.reflect.Method;

public class BeforeAdvisor extends StaticMethodMatcherPointcutAdvisor {

    public BeforeAdvisor(Advice advice) {
        super(advice);
    }

    @Override
    public int getOrder() {
        return -10;
    }

    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return method.getName().startsWith("find");
    }
}

最后Bean定义如下所示

@Bean
public SimpleAdvisor simpleAdvisor() {
    return new SimpleAdvisor();
}

@Bean
public BeforeAdvisor beforeAdvisor() {
    return new BeforeAdvisor(new SimpleBeforeAdvice());
}

@Bean
public AroundAdvisor aroundAdvisor() {
    return new AroundAdvisor(new SimpleMethodInteceptor());
}

排序参数大小分别为 10 -10 -15 最后advisor排序应该为aroundAdvisorbeforeAdvisorsimpleAdvisor
在这里插入图片描述
在这里插入图片描述
从执行结果来看:在方法执行之前的(前置增强),排序按照优先级先执行优先级高的,然后执行优先级低的,但是在方法执行之后的(后置增强),排序按照优先级先执行优先级低的,然后执行优先级高的。而环绕通知包含了前置与后置,会使情况复杂一些,但可以分成前置与后置来看。
以下为排序之前的执行效果

九月 27, 2020 3:50:40 下午 org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker postProcessAfterInitialization
信息: Bean 'rootConfig' of type [com.example.aop.advice.RootConfig$$EnhancerBySpringCGLIB$$53573a2f] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
-----SimpleBeforeAdvice-----😄😄findById增强-------------
----findById----User{userId=9527, name='周星星', age=18}
-----CountingAfterReturningAdvice-----findById--afterReturning-------------User{userId=9527, name='周星星', age=18}
*************************************
----SimpleMethodInteceptor--before proceed----update增强-------------
---UserService-add user----User{userId=9526, name='james', age=20}
----SimpleMethodInteceptor--after proceed----update增强-------------
-----CountingAfterReturningAdvice-----update--afterReturning-------------User{userId=9526, name='james', age=20}
九月 27, 2020 3:50:41 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@5197848c: startup date [Sun Sep 27 15:50:40 CST 2020]; root of context hierarchy

以下是排序之后的执行效果

九月 27, 2020 3:49:33 下午 org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker postProcessAfterInitialization
信息: Bean 'rootConfig' of type [com.example.aop.advice.RootConfig$$EnhancerBySpringCGLIB$$53573a2f] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
-----SimpleBeforeAdvice-----😄😄findById增强-------------
----findById----User{userId=9527, name='周星星', age=18}
-----CountingAfterReturningAdvice-----findById--afterReturning-------------User{userId=9527, name='周星星', age=18}
*************************************
----SimpleMethodInteceptor--before proceed----update增强-------------
---UserService-add user----User{userId=9526, name='james', age=20}
-----CountingAfterReturningAdvice-----update--afterReturning-------------User{userId=9526, name='james', age=20}
----SimpleMethodInteceptor--after proceed----update增强-------------
九月 27, 2020 3:49:34 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@5197848c: startup date [Sun Sep 27 15:49:33 CST 2020]; root of context hierarchy

可以看出CountingAfterReturningAdviceSimpleMethodInteceptor的执行顺序发生了变化。

  • 此处只会处理Advisor实现类,而Aspect注解的类并不支持。

3. AbstractAdvisorAutoProxyCreator

这是DefaultAdvisorAutoProxyCreator的超类。 如果advisor无法为框架DefaultAdvisorAutoProxyCreator的行为提供足够的自定义,则可以通过子类化此类来创建自己的自动代理创建者。
DefaultAdvisorAutoProxyCreator中提供了按照名称过滤器支持的功能,对应的方法为

@Override
protected boolean isEligibleAdvisorBean(String beanName) {
	return (!isUsePrefix() || beanName.startsWith(getAdvisorBeanNamePrefix()));
}

在有些场景下,需要额外的功能,则完全可以参照实现自己的子类。

二、AP原理分析

要分析AP的原理,首先来看一下DefaultAdvisorAutoProxyCreator的继承结构
在这里插入图片描述
首先是实现了一些类的xxxAware接口,这些接口保证DefaultAdvisorAutoProxyCreator在实例化之后回调相关方法设置BeanNameBeanFactory这些值。最关键的还是实现了SmartInstantiationAwareBeanPostProcessor接口。这样AbstractAutoProxyCreator在一个bean实例化、初始化的前后都可以进行相关的操作了。

第一个需要关注的是postProcessBeforeInstantiation这个接口方法,这个方法是在bean对象实例化之前生成代理的,如果这个方法不返回null,后续都不会执行。(这一块需要对Spring IOC有相当的理解才能看懂,但本文主要是讲解AOP的,所以此处不会详述这段逻辑)

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
	Object cacheKey = getCacheKey(beanClass, beanName);

	if (beanName == null || !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.
	if (beanName != null) {
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			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;
}

以上逻辑除了beanName不为null而且getCustomTargetSource返回有值才会进入到创建代理的逻辑返回不为null。getCustomTargetSource方法如下:

protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
	// We can't create fancy target sources for directly registered singletons.
	if (this.customTargetSourceCreators != null &&
			this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
		for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
			TargetSource ts = tsc.getTargetSource(beanClass, beanName);
			if (ts != null) {
				// Found a matching TargetSource.
				if (logger.isDebugEnabled()) {
					logger.debug("TargetSourceCreator [" + tsc +
							"] found custom TargetSource for bean with name '" + beanName + "'");
				}
				return ts;
			}
		}
	}

	// No custom TargetSource found.
	return null;
}

其中的customTargetSourceCreators只能通过参数的setter方法传入,默认情况下是没有值的。所以不会生成代理。

接下来的几个回调方法都是默认实现,与自动代理没啥关系

@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) {
	return true;
}

@Override
public PropertyValues postProcessPropertyValues(
		PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {

	return pvs;
}

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
	return bean;
}

还有一个就是org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference方法,这个方法也可以创建代理,但是只在解决循环依赖的时候才会调用。此处也不是重点。

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

最后一个 也就是最终要的方法postProcessAfterInitialization后置处理,此时对应的bean已经完成了实例化、属性填充、初始化前置处理、初始化。对应实现如下

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

生成代理过程
1. 此处earlyProxyReferences用于解决循环依赖,一般都是为空的,都会进入到wrapIfNecessary方法。

/**
 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
 * @param bean the raw bean instance
 * @param beanName the name of the bean
 * @param cacheKey the cache key for metadata access
 * @return a proxy wrapping the bean, or the raw bean instance as-is
 */
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {

2. 如果在targetSourcedBeans当中有值,那么在postProcessBeforeInstantiation方法中已经处理过了

	if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}

之前已经处理过 已经判断不需要进行代理的

	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
		return bean;
	}

3. 基础类不需要进行代理 哪些是基础类呢? Advice Pointcut Advisor AopInfrastructureBean这些都不需要生成代理 他们本身就是用来给别人生成代理的
shouldSkip默认返回false,子类可以覆盖这个方法实现自己的特定逻辑

	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

4.获取advice

	// Create proxy if we have advice.
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

getAdvicesAndAdvisorsForBean这个方法在AbstractAutoProxyCreator中是个抽象方法,在AbstractAdvisorAutoProxyCreator中实现如下

protected static final Object[] DO_NOT_PROXY = null;

@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
	List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
	if (advisors.isEmpty()) {
	    // 如果有效的Advisor不存在 则返回null
		return DO_NOT_PROXY;
	}
	// 存在有效的Advisor则返回数组对象
	return advisors.toArray();
}

查找合格的Advisor源码如下

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	extendAdvisors(eligibleAdvisors);
	if (!eligibleAdvisors.isEmpty()) {
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
	}
	return eligibleAdvisors;
}

分为三个步骤

  • 查找候选的Advisor
protected List<Advisor> findCandidateAdvisors() {
	return this.advisorRetrievalHelper.findAdvisorBeans();
}

其中advisorRetrievalHelper用于从bean工厂当中获取所有的Advisor。在设置对象的BeanFactory属性之后进行初始化。

private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper;


@Override
public void setBeanFactory(BeanFactory beanFactory) {
	super.setBeanFactory(beanFactory);
	if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
		throw new IllegalArgumentException(
				"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
	}
	initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}

protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}

进行查找

/**
 * Find all eligible Advisor beans in the current bean factory,
 * ignoring FactoryBeans and excluding beans that are currently in creation.
 * @return the list of {@link org.springframework.aop.Advisor} beans
 * @see #isEligibleBean
 */
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!
		advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this.beanFactory, Advisor.class, true, false);
		this.cachedAdvisorBeanNames = advisorNames;
	}
	if (advisorNames.length == 0) {
		return new ArrayList<Advisor>();
	}

	List<Advisor> advisors = new ArrayList<Advisor>();
	for (String name : advisorNames) {
		if (isEligibleBean(name)) {
			if (this.beanFactory.isCurrentlyInCreation(name)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping currently created advisor '" + name + "'");
				}
			}
			else {
				try {
					advisors.add(this.beanFactory.getBean(name, Advisor.class));
				}
				catch (BeanCreationException ex) {
					Throwable rootCause = ex.getMostSpecificCause();
					if (rootCause instanceof BeanCurrentlyInCreationException) {
						BeanCreationException bce = (BeanCreationException) rootCause;
						if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
							if (logger.isDebugEnabled()) {
								logger.debug("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;
}

其中最重要的三行就是获取所有Advisor类型Bean的名称

advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
					this.beanFactory, Advisor.class, true, false);

遍历然后判断是否有效,此处固定为true

protected boolean isEligibleBean(String beanName) {
	return true;
}

获取Bean对象并添加到列表当中

advisors.add(this.beanFactory.getBean(name, Advisor.class));
  • 过滤获取合格的Advisor(根据bean的类型和方法进行匹配)
    主要根据bean的类型进行过滤
/**
 * 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<Advisor> findAdvisorsThatCanApply(
		List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

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

对应方法为org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply

/**
 * 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<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
	if (candidateAdvisors.isEmpty()) {
		return candidateAdvisors;
	}
	List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
	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;
}

考虑是否为引介增强IntroductionAdvisor.针对引介增强判断如下

/**
 * 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.
 * @param advisor the advisor to check
 * @param targetClass class we're testing
 * @return whether the pointcut can apply on any method
 */
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
	return canApply(advisor, targetClass, false);
}
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;
	}
}

从这里不难看出,针对引介增强IntroductionAdvisor的判断依据也是通过自定义的类过滤器进行匹配。
如果是PointcutAdvisor,首先按照类型过滤器进行匹配,如果类型匹配,还需要看方法匹配器,二者匹配才返回true.
如果两者都不是(这种情况比较少),则认为匹配成功。

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
	Assert.notNull(pc, "Pointcut must not be null");
	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<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
	classes.add(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;
}
  • 按照规则进行排序
    在上面的排序支持中已经详细探讨过
    5.创建代理
	if (specificInterceptors != DO_NOT_PROXY) {
		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;
}

考虑到可能重复判断,所以这里首先考虑到通过advisedBeans缓存。

private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<Object, Boolean>(256);

创建代理主要是createProxy方法。源码如下

protected Object createProxy(
		Class<?> beanClass, String beanName, 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());
}

如果看过上一章博客的话,是不是非常熟悉。

三、注解EnableAspectJAutoProxy原理

在本系列一开始,我们就通过注解EnableAspectJAutoProxy开启自动代理支持,通过这个注解不仅仅支持Advisor,而且支持@Aspect注解。是如何实现的呢?

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
	 * to standard Java interface-based proxies. The default is {@code false}.
	 */
	boolean proxyTargetClass() default false;

	/**
	 * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
	 * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
	 * Off by default, i.e. no guarantees that {@code AopContext} access will work.
	 * @since 4.3.1
	 */
	boolean exposeProxy() default false;
}

在配置类中添加了这样的注解,在ConfigurationClassPostProcessor起作用的时候会根据AspectJAutoProxyRegistrar的方法进行bean的注册

ConfigurationClassPostProcessor是Spring中的关键类 参考博客:ConfigurationClassPostProcessor

public void registerBeanDefinitions(
		AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

	AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

	AnnotationAttributes enableAspectJAutoProxy =
			AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
	if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
		AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
	}
	if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
		AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
	}
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
	return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
	return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

可以看出这里主要是注册了一个AnnotationAwareAspectJAutoProxyCreator类型的bean。
在这里插入图片描述
可以看出这个类最终也实现了抽象类AbstractAdvisorAutoProxyCreator.

首先在类AspectJAwareAdvisorAutoProxyCreator中覆盖了shouldSkip方法

@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
	// TODO: Consider optimization by caching the list of the aspect names
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	for (Advisor advisor : candidateAdvisors) {
		if (advisor instanceof AspectJPointcutAdvisor) {
			if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
				return true;
			}
		}
	}
	return super.shouldSkip(beanClass, beanName);
}

AnnotationAwareAspectJAutoProxyCreator中覆盖了findCandidateAdvisors方法

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

除了父类中查找Advisor类型Bean,增加了通过BeanFactoryAspectJAdvisorsBuilder查找注解了Aspect的类并转化为Advisor。

/**
 * Look for AspectJ-annotated aspect beans in the current bean factory,
 * and return to a list of Spring AOP Advisors representing them.
 * <p>Creates a Spring Advisor for each AspectJ advice method.
 * @return the list of {@link org.springframework.aop.Advisor} beans
 * @see #isEligibleBean
 */
public List<Advisor> buildAspectJAdvisors() {
	List<String> aspectNames = this.aspectBeanNames;

	if (aspectNames == null) {
		synchronized (this) {
			aspectNames = this.aspectBeanNames;
			if (aspectNames == null) {
				List<Advisor> advisors = new LinkedList<Advisor>();
				aspectNames = new LinkedList<String>();
				String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
						this.beanFactory, Object.class, true, false);
				for (String beanName : beanNames) {
					if (!isEligibleBean(beanName)) {
						continue;
					}
					// We must be careful not to instantiate beans eagerly as in this case they
					// would be cached by the Spring container but would not have been weaved.
					Class<?> beanType = this.beanFactory.getType(beanName);
					if (beanType == null) {
						continue;
					}
					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<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;
			}
		}
	}

	if (aspectNames.isEmpty()) {
		return Collections.emptyList();
	}
	List<Advisor> advisors = new LinkedList<Advisor>();
	for (String aspectName : aspectNames) {
		List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
		if (cachedAdvisors != null) {
			advisors.addAll(cachedAdvisors);
		}
		else {
			MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
			advisors.addAll(this.advisorFactory.getAdvisors(factory));
		}
	}
	return advisors;
}

总结

从以上分析不难看出,Spring AOP自动代理原理其实并不复杂,通过Spring后置处理器在Bean实例化之前或者Bean初始化之后,从容器中获取可用的Advisor,这其中就包括了PointcutAdvisorIntroductionAdvisor、通过@Aspect类构造的Advisor,然后再根据Bean的类类型和方法进行类型过滤和方法匹配,这些在前面章节都单独介绍过。过滤完成之后再排序,在根据这些增强逻辑生成代理。因为满足代理的条件的这个目标bean通过实例化、初始化就能完成所需的代理过程,而不需要通过原始API一个一个手动创建代理。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lang20150928

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值