文章目录
前言
在前面几章,我们从原始Java API来介绍了AOP中涉及到的各个部分:Advice
、Pointcut
、Advisor
,通过ProxyFactoryBean
、ProxyFactory
来创建代理, 可是,仅仅这样还不能让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
中用法一直,可以是Interceptor
、Advice
、Advisor
.
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
)的优点。
使用此机制涉及:
- 指定
DefaultAdvisorAutoProxyCreator
Bean定义。 - 在相同或相关的上下文中指定任意数量的
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;
}
有几点需要注意
- 在配置类中使用
@Order
注解是无效的,必须放在对应类上面。如下案例是无效的
@Order(10)
@Bean
public SimpleAdvisor simpleAdvisor() {
return new SimpleAdvisor();
}
如下案例是有效的
@Order(10)
public class SimpleAdvisor implements PointcutAdvisor {
- 如果继承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排序应该为aroundAdvisor
、beforeAdvisor
、simpleAdvisor
。
从执行结果来看:在方法执行之前的(前置增强
),排序按照优先级先执行优先级高的,然后执行优先级低的,但是在方法执行之后的(后置增强
),排序按照优先级先执行优先级低的,然后执行优先级高的。而环绕通知包含了前置与后置,会使情况复杂一些,但可以分成前置与后置来看。
以下为排序之前的执行效果
九月 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
可以看出CountingAfterReturningAdvice
与SimpleMethodInteceptor
的执行顺序发生了变化。
- 此处只会处理Advisor实现类,而Aspect注解的类并不支持。
3. AbstractAdvisorAutoProxyCreator
这是DefaultAdvisorAutoProxyCreator
的超类。 如果advisor
无法为框架DefaultAdvisorAutoProxyCreator
的行为提供足够的自定义,则可以通过子类化此类来创建自己的自动代理创建者。
在DefaultAdvisorAutoProxyCreator
中提供了按照名称过滤器支持的功能,对应的方法为
@Override
protected boolean isEligibleAdvisorBean(String beanName) {
return (!isUsePrefix() || beanName.startsWith(getAdvisorBeanNamePrefix()));
}
在有些场景下,需要额外的功能,则完全可以参照实现自己的子类。
二、AP原理分析
要分析AP的原理,首先来看一下DefaultAdvisorAutoProxyCreator
的继承结构
首先是实现了一些类的xxxAware
接口,这些接口保证DefaultAdvisorAutoProxyCreator
在实例化之后回调相关方法设置BeanName
、BeanFactory
这些值。最关键的还是实现了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,这其中就包括了PointcutAdvisor
、IntroductionAdvisor
、通过@Aspect类构造的Advisor,然后再根据Bean的类类型和方法进行类型过滤和方法匹配,这些在前面章节都单独介绍过。过滤完成之后再排序,在根据这些增强逻辑生成代理。因为满足代理的条件的这个目标bean通过实例化、初始化就能完成所需的代理过程,而不需要通过原始API一个一个手动创建代理。