前言
上篇文章讲解了AOP解析工作,将配置文件解析并封装成beanDefinition,由于配置文件中有5个通知方法,before、after、around、after-returning、after-throwing,这里会将其解析成5个advisor通知类。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="accountAdvice" class="service.impl.AccountAdvice" ></bean>
<bean id="myAccount" class="service.impl.MyAccount" ></bean>
<aop:config>
<aop:pointcut id="pointCut" expression="execution(* service.impl.*.*())"/>
<aop:aspect ref="accountAdvice">
<aop:after method="after" pointcut-ref="pointCut"></aop:after>
<aop:before method="before" pointcut-ref="pointCut"></aop:before>
<aop:around method="around" pointcut-ref="pointCut"></aop:around>
<aop:after-returning method="afterReturn" pointcut-ref="pointCut"></aop:after-returning>
<aop:after-throwing method="afterThrow" pointcut-ref="pointCut"></aop:after-throwing>
</aop:aspect>
</aop:config>
</beans>
解析后的BeanDefinitions集合信息:
正文
之前Spring IOC文章讲解过Bean的实例化过程,在实例化Bean之后会进行属性填充(populateBean)、执行初始化方法(initializeBean)。而代理类的生成就在执行初始化方法(initializeBean)中,在该方法中会执行beanPostProcessor方法,如果该bean需要代理,则会进行代理工作。
本章案例中需要被代理的类是myAccount,所以我们来到myAccount实例化过程中的initializeBean方法中;
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 如果安全管理器不为空
if (System.getSecurityManager() != null) {
// 以特权的方式执行回调bean中的Aware接口方法
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// Aware接口处理器,调用BeanNameAware、BeanClassLoaderAware、beanFactoryAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
//如果mdb不为null || mbd不是"synthetic"。一般是指只有AOP相关的prointCut配置或者Advice配置才会将 synthetic设置为true
if (mbd == null || !mbd.isSynthetic()) {
// 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessBeforeInitialization初始化方法。
// 返回的Bean实例可能是原始Bean包装器
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//调用初始化方法,先调用bean的InitializingBean接口方法,后调用bean的自定义初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
//捕捉调用初始化方法时抛出的异常,重新抛出Bean创建异常:调用初始化方法失败
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
//如果mbd为null || mbd不是"synthetic"
if (mbd == null || !mbd.isSynthetic()) {
// 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessAfterInitialization方法。
// 返回的Bean实例可能是原始Bean包装器
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
//返回包装后的Bean
return wrappedBean;
}
AOP的代理类生成过程在BeanPostProcessor的after方法中调用
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName),见方法1详解
方法1:postProcessAfterInitialization
进入到AspectJAwareAdivsorAutoProxyCreator类中的postProcessAfterInitialization方法;
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 获取当前bean的key:如果beanName不为空,则以beanName为key,如果为FactoryBean类型则beanName名称前面会加上“&”符号
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 判断当前bean是否正在被代理,如果正在被代理则不进行代理操作
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果它需要被代理,则需要封装指定的bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
wrapIfNecessary(bean, beanName, cacheKey),见方法2详解
方法2:wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 判断是否已经处理过,处理过则直接返回
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 这里advisedBeans缓存了已经进行了代理流程处理的bean,如果缓存中存在,则可以直接返回
//这里存在两种bean,一种是不需要代理的bean,一种是真正需要代理的,避免下次判断时可以直接返回,不走下面处理逻辑
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 这里isInfrastructureClass()用于判断当前bean是否为Spring系统自带的bean,如:Advice、Pointcut、Advisor、AopInfrastructureBean的实现类
// 不用进行代理的;shouldSkip()则用于判断当前bean是否应该被略过
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
// 对当前bean进行缓存
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 尝试获取能够匹配当前被代理类的通知类信息
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果找到合适的通知类,则进行代理操作
if (specificInterceptors != DO_NOT_PROXY) {
// 对当前bean的代理状态进行缓存
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 根据获取到的Advices和Advisors为当前bean生成代理对象
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// 缓存生成的代理bean的类型,并且返回生成的代理bean
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
shouldSkip(bean.getClass(), beanName),见方法3详解
getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null),见方法4详解
createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)),见方法7详解
方法3:shouldSkip
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
//尝试从beanFacotry工厂中获取配置文件中定义好的五个通知方法,它们被封装成了advisor对象,所以这里能获取到5个
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
//判断通知类中的切面类名称,如果当前bean是切面类,则不应该被代理,会跳过
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
方法4:getAdvicesAndAdvisorsForBean
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 找合适的增强器对象
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();
// 对获取到的所有Advisor进行判断,判断其中的表达式是否能够匹配上要被代理的类
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 提供的hook方法,用于对目标Advisor进行扩展
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 对需要代理的Advisor按照一定的规则进行排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName),见方法5详解
extendAdvisors(eligibleAdvisors),见方法6详解
方法5:findAdvisorsThatCanApply
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 从候选的通知器中找到合适正在创建的实例对象的通知器
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
// 若候选的增强器集合为空 直接返回
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
// 定义一个合适的增强器集合对象
List<Advisor> eligibleAdvisors = new ArrayList<>();
// 循环我们候选的通知类对象
for (Advisor candidate : candidateAdvisors) {
// 判断我们的通知类对象是不是实现了IntroductionAdvisor
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
// 判断是否有合适的通知类
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
// 判断我们的通知类对象是不是实现了IntroductionAdvisor
if (candidate instanceof IntroductionAdvisor) {
// already processed
// 在上面已经处理过,不需要处理
continue;
}
// 真正的判断增强器是否合适当前类型,这里会通过切入点表达式进行判断是否适用于当前类
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
方法6:extendAdvisors
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not required
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
for (Advisor advisor : advisors) {
// Be careful not to get the Advice without a guard, as this might eagerly
// instantiate a non-singleton AspectJ aspect...
//判断是否是通知类,并将其属性打上标签
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
break;
}
}
//这里会往advisors缓存中添加ExposeInvocationInterceptor对象,该对象为后续代理类调用过程中的拦截链做准备
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
方法7:createProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
// 给bean定义设置暴露属性
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
// 获取当前类中相关属性
proxyFactory.copyFrom(this);
// 决定对于给定的bean是否应该使用targetClass而不是他的接口代理,检查proxyTargetClass设置以及preserverTargetClass属性
if (!proxyFactory.isProxyTargetClass()) {
// 判断是 使用jdk动态代理 还是cglib代理
//如果被代理类有preserveTargetClass,则设置ProxyTargetClass为true,尝试使用Cglib进行代理
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 判断是否有实现接口,如果没有实现接口则设置setProxyTargetClass为true,尝试使用Cglib进行代理
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 将被代理类名称及其适配的通知对象构建通知类
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
// 设置到要代理的类
proxyFactory.setTargetSource(targetSource);
//空方法,用于子类拓展实现
customizeProxyFactory(proxyFactory);
// 控制代理工程被配置之后,是否还允许修改通知,默认值是false
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 真正创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
proxyFactory.getProxy(getProxyClassLoader()),见方法8详解
方法8:getProxy
public Object getProxy(@Nullable ClassLoader classLoader) {
// createAopProxy() 用来创建我们的代理工厂
return createAopProxy().getProxy(classLoader);
}
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
// 监听调用AdvisedSupportListener实现类的activated方法
activate();
}
// 通过AopProxyFactory获得AopProxy,这个AopProxyFactory是在初始化函数中定义的,使用的是DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}
getAopProxyFactory().createAopProxy(this),见方法9详解
方法9:createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 这段代码用来判断选择哪种创建代理对象的方式
// config.isOptimize() 是否对代理类的生成使用策略优化 其作用是和isProxyTargetClass是一样的 默认为false
// config.isProxyTargetClass() 是否使用Cglib的方式创建代理对象 默认为false
// hasNoUserSuppliedProxyInterfaces目标类是否有接口存在 且只有一个接口的时候接口类型是SpringProxy类型
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
// 上面的三个方法有一个为true的话,则进入到这里
// 从AdvisedSupport中获取被代理类
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.");
}
// 判断目标类是否是接口 如果目标类是接口的话,则还是使用JDK的方式生成代理对象
// 如果目标类是Proxy的子类或其实现类时,使用JDK动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 配置了使用Cglib进行动态代理或者目标类没有接口,那么使用Cglib的方式创建代理对象
return new ObjenesisCglibAopProxy(config);
}
else {
// 使用JDK的提供的代理方式生成代理对象
return new JdkDynamicAopProxy(config);
}
}
JDK动态代理根Cglib动态代理在前面的文章中我们讲解过其源码实现过程,可以看这两篇文章进行学习,过程跟Spring AOP过程差不多。
《动态代理:Cglib原理讲解》
《动态代理:JDK动态代理源码学习》
总结
- 当切面类指定了proxy-target-class="true"属性时,代表要使用Cglib(proxyTargetClass属性会为true),此时有机会是Cglib代理。
- 条件1不满足时,看被代理类是否有preserverTargetClass属性,且值为true时,会将proxyTargetClass属性设置为true,此时有机会是Cglib代理。
- optimize为true时,此时有机会是Cglib代理。
- 被代理类只有一个接口,并且该接口是SpringProxy类型,此时有机会是Cglib代理。
- 被代理类没有实现接口,此时会将proxyTargetClass属性设置为true,此时有机会是Cglib代理。
以上5个条件满足其中1个,且被代理类不是接口或不是Proxy的子类或者实现类时使用Cglib代理。
因此,我们可以得出结论:
- 被代理类没有接口时不一定使用Cglib进行代理,因为可能被代理类是一个接口或者是Proxy的子类或者实现类
- 被代理类有接口时不一定使用JDK进行代理:
- 有可能切面类指定了proxyTargetClass为true
- 有可能被代理类的只有一个接口且是SpringProxy类型
- 有可能代理工厂的optimize属性为true