aop源码解析三-postProcessAfterInitialization

本文深入探讨Spring AOP的源码,重点关注`postProcessAfterInitialization`方法,揭示代理对象的创建过程。文章介绍了如何通过`BeanPostProcessor`进行后初始化处理,涉及切点匹配、代理类型选择,并详细讲解了`AdvisedSupport`和`ProxyFactoryBean`的角色,以及Java动态代理的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

aop源码解析二:postProcessBeforeInstantiation博文中 我们花了很长的一个篇幅介绍一个方法shouldSkip方法 虽然看名字很简单 但里面确实做了很多的事情 虽然最终也是没有去创建代理 但这些工作并不是白做的 解析完以后缓存起来了 后面就可以直接使用了 这次我们看下AnnotationAwareAspectJAutoProxyCreator##postProcessAfterInitialization(Object bean, String beanName)方法

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

在这里看到了我们一直想看到的代理相关的代码 因为创建代理是一件耗时的事情 要做很多的解析 转换等工作 所以根据beanClass``beanName作为缓存的key

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        // 因为寻找切面方法等操作是很浪费时间的操作 所以如果不必操作的话或者已经创建过代理的话 尽量提前返回
        //已经创建过
        if (beanName != null && this.targetSourcedBeans.containsKey(beanName)) {
            return 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;
        }

        // 可以看出作者的思路是很清晰的 几句代码概括了要做的事情 然后在方法里面展开
        // advice advisor pointcut 等之间的名次的区别与联系
        // advice : action to take at a joinpoint
        // 1. 寻找适合此bean的切面方法
        // 2. 创建代理
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            //创建代理对象 java动态代理或者是基于cglib的代理 cglib代理更高效
            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;
    }

我们又看到了shouldSkip(bean.getClass(), beanName)方法 跟我们上篇博文介绍的是同一个方法
这里主要看下getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null)方法
其实这个方法的主要作用是对于寻找到的所有的切面对beanClass做过滤 涉及到切点的匹配 例如正则表达式 注解等

    @Override
    protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
        // 寻找胜任的或者说适合此bean的advior
        List advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
    }


        protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {
        //Advisor.class
        //寻找所有的候选项
        // 这里注意 findCandidateAdvisors() 方法在AnnotationAwareAspectJAutoProxyCreator类有继承
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        //从候选项中挑出适合此bean的advisor
        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            //对advisor排序 按照顺序:
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }

findCandidateAdvisors()方法 我们在介绍shouldSkip(xxx)方法的时候就已经讲解过 不熟悉的读者可以多读几遍 这个方法解析出了所有的advisor advisor包括advice``pointcut信息

    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 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;
            }
            //todo 写注释
            if (canApply(candidate, clazz, hasIntroductions)) {
                eligibleAdvisors.add(candidate);
            }
        }
        return eligibleAdvisors;
    }

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

        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();
        IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
        if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
            introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
        }
        // 类继承关系中 只要有一个类的一个方法被匹配 就返回true
        Set<Class> classes = new LinkedHashSet<Class>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
        classes.add(targetClass);
        for (Class<?> clazz : classes) {
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                if ((introductionAwareMethodMatcher != null &&
                        introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
                        methodMatcher.matches(method, targetClass)) {
                    return true;
                }
            }
        }

        return false;
    }

最重要的还是最后一个canApply方法 根据pointcut信息去做匹配 判断是否符合要求 因为这里是返回类的代理 所以只要有一个方法被匹配到 就人为满足条件 至于是怎么做匹配的 感兴趣的读者可以深入阅读 我们这里只要知道做了什么就可以了
回到wrapIfNecessary方法 继续往下看 下面的就是我们一直想看到的方法了 创建代理
看一下aop的相关配置

<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>

这行代码注册了BPP 另外还指定了proxy-target-class属性 值为true的意思是强制使用cglib创建代理 还有另外一种java jdk提供的代理 需要被代理的类的方法继承自某个接口方法才可以 cglib并没有这个限制 推荐使用cglib的方式 执行速度更快
但我们下面是以jdk创建代理为例讲解 这种方式更简单 读者也可能更熟悉这种方式 那么就把这行xml配置改成下面这样

<aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="true"/>

对java提供的动态代理实现不了解的读者 建议先看这篇博客java动态代理介绍 这样下面的代理就更容易理解
我们看下createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean))方法

protected Object createProxy(
            Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

        ProxyFactory proxyFactory = new ProxyFactory();
        // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
        proxyFactory.copyFrom(this);

        //使用java动态代理
        if (!shouldProxyTargetClass(beanClass, beanName)) {
            // Must allow for introductions; can't just set interfaces to
            // the target's interfaces only.
            Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
            for (Class<?> targetInterface : targetInterfaces) {
                proxyFactory.addInterface(targetInterface);
            }
        }

        //
        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        for (Advisor advisor : advisors) {
            proxyFactory.addAdvisor(advisor);
        }

        proxyFactory.setTargetSource(targetSource);
        customizeProxyFactory(proxyFactory);

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

        return proxyFactory.getProxy(this.proxyClassLoader);
    }

ProxyFactory是一个很重要的类 里面有各种与切面相关的属性,方法等

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

getProxy(ClassLoader classLoader)方法返回的就是目标类的代理类 分成两大步完成

  • 返回要使用的AopProxy CglibAopProxy或者JdkDynamicAopProxy
  • 创建代理
    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        //默认是DefaultAopProxyFactory
        return getAopProxyFactory().createAopProxy(this);
    }

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            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.");
            }
            if (targetClass.isInterface()) {
                return new JdkDynamicAopProxy(config);
            }
            return CglibProxyFactory.createCglibProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

默认使用的创建AopProxy的是DefaultAopProxyFactory 是一个工厂类 类的实现很简单 根据条件返回对应的AopProxy 当然都把proxyFactory作为参数传递了进去
我们接下来看JdkDynamicAopProxy##getProxy方法

public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
        //寻找equals hashCode方法
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

completeProxiedInterfaces(AdvisedSupport advised) 方法在代理类要实现的所有接口中加入了两个接口SpringProxyAdvised接口 SpringProxy是一个标志接口 没有什么方法需要去实现 Advised提供的接口方法就比较多了 里面有代理相关的所有配置属性
下面就是创建代理了 相信读者如果阅读了java动态代理介绍这篇博客的话 读者应该理解做了什么事情 在下一篇博客中我们看一下方法的调用过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值