Spring AOP源码详解之创建代理对象

前在Spring IoC源码详解之InitializeBean中提到过创建Spring AOP代理对象的留下就在执行bean后置处理器的postProcessAfterInitialization方法中。更具体一点是执行AnnotationAwareAspectJAutoProxyCreator处理器的父类AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization的方法中完成的。

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    invokeInitMethods(beanName, wrappedBean, mbd);
    
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}

我们具体来看看它的方法实现:

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        // 如果是普通bean,则返回beanName,如果是FactoryBean,则返回加上前缀&的&beanName
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        // earlyProxyReferences中缓存的是已经创建好的代理对象
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

getCacheKey的作用是:如果是对于普通bean,则返回beanName,如果是FactoryBean,则返回加上前缀&的&beanName。然后根据cacheKey去earlyProxyReferences这个缓存中看看该代理对象是否已经被创建过了,如果创建过直接返回bean。否则进入wrapIfNecessary方法。

1. 判断是否需要被代理
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 也是看看有没有缓存,有缓存对象就直接返回了。
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    // 如果该bean不需要被代理,则直接返回原始的bean对象
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    // 
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    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缓存中获取要代理的原始对象,如果它不需要被代理的话也直接返回原始对象。值得注意的是在IOC启动过程中,第一次进入advisedBeans这个缓存中是没有值的。isInfrastructureClass和shouldSkip在上一篇文章已经分析过,这里不再赘述。其对应的if分支是不会进入。重点放在方法getAdvicesAndAdvisorsForBean,该方法又主要委托findEligibleAdvisors来实现寻找advisor的逻辑,所以我们直接来看findEligibleAdvisors

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 获取所有已经解析完成的advisor
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 根据beanClass过滤candidateAdvisors中的advisor
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

findCandidateAdvisors将找到的advisor放入到candidateAdvisors中(详细分析请见上一篇文章)。随后在findEligibleAdvisors中根据beanClass过滤除适用的advisor。最终执行的方法是在AopUtils#findAdvisorsThatCanApply

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    if (candidateAdvisors.isEmpty()) {
        return candidateAdvisors;
    }
    List<Advisor> 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;
}

Advisor分为IntroductionAdvisor和PointcutAdvisor两种,我们使用的绝大部分Advisor都是PointcutAdvisor。canApply方法可以用来确认所给定的类上advisor是否可以被应用。最后返回过滤后可以被应用在给定类上的advisors。以OperationUtil.class为例,OperationAop.class中的三个Advice都可以被作用在OperationUtil.class上;而其余的类则一个也没有。

返回到findEligibleAdvisors中执行extendAdvisors方法,该方法会添加一个DefaultPointcutAdvisor到eligibleAdvisors中。如果使用AspectJ的切点表达式,则会使用AspectJExpressionPointcutAdvisor;如果使用名称匹配切点的方式,则用NameMatchMethodPointcutAdvisor;如果使用正则匹配切点的方式,则使用RegexpMethodPointcutAdvisor;如果使用其他方式,比如用户自定义切点的方式,那么就使用DefaultPointcutAdvisor。随后的排序会将刚刚添加进入的DefaultPointcutAdvisor排到第一个位置。

B4FFFA46-CE4B-E982-83D6-ADE09CA6E53A.png

最终wrapIfNecessary方法Object[] specificInterceptors得到的结果就是刚刚返回的eligibleAdvisors。如果specificInterceptors不为null,就advisedBeans.put(cacheKey, Boolean.TRUE),将对应的bean添加到全局的advisedBeans中,并且value是true,代表该bean需要被代理。接下来就是通过createProxy方法创建代理类了。

2. 创建代理类createProxy
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);
        }
    }
    // 就是把specificInterceptors中的advisors和commonInterceptors中的拦截器合并(如果有的话)在一起封装成Advisor返回
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // 将advisors和源对象设置到proxyFactory上
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }
    // 真正去创建代理对象了
    return proxyFactory.getProxy(getProxyClassLoader());
}

exposeTargetClass这个步骤看了很久才明白Spring的意思。下面简单说下我的理解:

走到这里就已经能肯定代理类是会创建的了,所以可以提前“曝光”它的原始类。expose一词是公之于众的意思,在这里也就是告诉其他bean:大家来看看啊,当前正在创建的bean(比如是OperationUtil)即将要青蛙变王子了!

怎么做到公之于众呢?Spring的做法是在方法内部在正常创建的bean的bd(全写是BeanDefinition)中设置上一个属性<"originalTargetClass",OperationUtil.class>。而bd是存放在bdmap中,bdmap又是由bean工厂直接管理。创建bean必须要有bean工厂的参与,这样就意味着只要在bd中增加一个属性就相当于对其他bean可见了。

接下来创建一个ProxyFactory,并从当前bean后置处理器AnnotationAwareAspectJAutoProxyCreator中获取参数初始化自身。然后确定代理方式是通过接口代理还是类继承代理。通过接口代理使用JDK自身提供的动态代理就能实现,而其他的代理只能通过Cglib实现动态代理。proxyTargetClass默认是false使用JDK代理,如果是true则使用Cglib。

接下来的buildAdvisors是把specificInterceptors中的advisors和commonInterceptors中的拦截器合并(如果有的话)在一起封装成Advisor返回。随后在proxyFactory对象上进行设置。这里targetSource就是被代理的bean对象。

最后就到了执行真正的创建逻辑了。

public Object getProxy(@Nullable ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}


public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        // 获得被代理对象的类型
        Class<?> targetClass = config.getTargetClass();
        // 如果对象类型是接口,或者是JAVA的动态代理类,那么就调用JDK的动态代理方法生成代理对象
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        // 否则使用CGLIB生成代理对象
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

// JDK动态代理
public Object getProxy(@Nullable ClassLoader classLoader) {
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

从config中拿出被代理对象的类型,然后判断该对象是否是接口或者是java的动态代理类。如果是则创建JdkDynamicAopProxy工厂,否则创建Cglib的ObjenesisCglibAopProxy工厂。随后调用对应Proxy工厂的getProxy方法创建代理对象。以创建JDK动态代理为例,最终会调用JAVA提供的Proxy.newProxyInstance动态代理方法代理对象后返回。


到此,Spring AOP的代理对象创建过程源码就分析的差不多了。总结一下:在bean的创建过程中,先实例化完成被代理对象并完成依赖注入后,进行到初始化bean的阶段。利用bean后置处理器AnnotationAwareAspectJAutoProxyCreator的applyBeanPostProcessorsAfterInitialization方法实现对目标对象的代理任务。任务进行过程中大致可以分为2步:1.获取之前已经解析好的advisors,逐个判断目标代理对象是否可以适用。2.如果使用则创建代理工厂,然后判断代理类型是通过接口还是通过类,如果是通过接口就由JDK动态代理生成代理对象,否则使用 Cglib来做这件事。

3. 附录:本工程项目文件

86133BAF-C2CF-60C1-CE29-E5279F892AB6.png

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HodayDouble {
}
@Aspect
@Component
public class OperationAop {

    @Pointcut("@annotation(com.Hodey.analyseaop.anno.HodayDouble)")
    public void doCut(){}

    @Around("doCut()")
    public int doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object[] args = proceedingJoinPoint.getArgs();
        int i = (int) args[0];
        int j = (int) args[1];
        System.out.println("入参:i:" + i);
        System.out.println("入参:j:" + j);
        System.out.println("before around");
        int result = (int) proceedingJoinPoint.proceed();
        System.out.println("after around");
        System.out.println("原始结果:" + result);

        result = result * 2;
        System.out.println("代理结果:" + result);
        return result;
    }

    @Before("doCut()")
    public void doBefore(){
        System.out.println("@Before print");
    }

    @After("doCut()")
    public void doAfter(){
        System.out.println("@After print");
    }
}
@Service("service")
public class OperationService {

    @Autowired
    private OperationUtil ops;

    public int add(int i , int j){
        return ops.add(i,j);
    }
}
@Component
public class OperationUtil {

    @HodayDouble
    public int add(int i, int j){
        int result = i + j;
        return result;
    }
}
@ComponentScan("com.Hodey")
@EnableAutoConfiguration
public class AnalyseAopApplication {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AnalyseAopApplication.class);
		OperationService opsService = (OperationService) ctx.getBean("service");
		int result = opsService.add(2,3);
		System.out.println("最终结果:" + result);
	}
}

执行结果:

入参:i:2
入参:j:3
before around
@Before print
after around
原始结果:5
代理结果:10
@After print
最终结果:10
收藏 (0)
评论列表
正在载入评论列表...
我是有底线的
为您推荐
    暂时没有数据