简单的 Spring Aop 原理剖析

spring aop
aop 的全称是Aspect-Oriented Programming(面向切面编程),怎么理解面向切面这句话?可以这么理解:每一个类的一个方法是一个点,同时处理多个点也就
可以理解为处理一个面,这个面包含多个点。概念部分也就更明显了,需要被处理的点叫做Pointcut(切点),处理的动作叫做Advice(通知),将切面和点连接在一起的策略叫做Advisor(通知器)。

《简单的 Spring Aop 原理剖析》

这里呢,只看一个包org.springframework.aop,直觉告诉我,这是最核心的包。把aop的源码导进eclipse看看,从aop包中看到,Pointcut、Advice、Proxy、Method出现的次数很多

《简单的 Spring Aop 原理剖析》

他们之间的关系怎样,导进powerdesigner 在整理一下,看看这些类之间的关系,其它的不做说明,我只看aop3个最主要的内容,Pointcut、Advice、Advisor。

Filter、Method

《简单的 Spring Aop 原理剖析》

Advice

《简单的 Spring Aop 原理剖析》

Advisor

《简单的 Spring Aop 原理剖析》

*其它

《简单的 Spring Aop 原理剖析》

以上4张图,仅仅是描述aop的架构,但是,具体怎么与IOC中bean相结合,这点卡了很久,突破口是代理!spring的代理主要有两种,一种是jdk动态代理,一种是CGLIB,根据我的分析,spring用的应该是jdk代理,因为接口太多了,通过接口实现类达到代理的效果。在org.springframework.aop.framework.autoproxy包中,有一个AbstractAutoProxyCreator.java类,从注释上看,aop的代理动作是通过拦截器完成的。而继承AbstractAutoProxyCreator的子类也可以用自己的策略按照类型、名称自动代理bean。

《简单的 Spring Aop 原理剖析》
《简单的 Spring Aop 原理剖析》

看看该类里面的postProcessAfterInitialization方法:

/** * Create a proxy with the configured interceptors if the bean is * identified as one to proxy by the subclass. * @see #getAdvicesAndAdvisorsForBean */
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (!this.earlyProxyReferences.contains(cacheKey)) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

结合注释,从缓存中找bean的代理,实在找不到了再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) {
        if (this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        if (this.nonAdvisedBeans.contains(cacheKey)) {
            return bean;
        }
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.nonAdvisedBeans.add(cacheKey);
            return bean;
        }

        // Create proxy if we have advice.
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.add(cacheKey);
            Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }

        this.nonAdvisedBeans.add(cacheKey);
        return bean;
    }

结合注释,成功创建的代理对象都会将beanName加入到targetSourceBeans中,从代码可以看到,是用createProxy方法创建的代理

/** * Create an AOP proxy for the given bean. * @param beanClass the class of the bean * @param beanName the name of the bean * @param specificInterceptors the set of interceptors that is * specific to this bean (may be empty, but not null) * @param targetSource the TargetSource for the proxy, * already pre-configured to access the bean * @return the AOP proxy for the bean * @see #buildAdvisors */
    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);

        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中创建的,在追踪,看看ProxyFactory

《简单的 Spring Aop 原理剖析》

这里不多说,但是从源码看到Interfaces 和 class两个关键字,可以推算,ProxyFactory一定是根据代理的方式决定采用哪种代理方式,基于Interfaces的是jdk动态代理,基于class的是cglib代理方式。
再回到createProxy中来,不管ProxyFactory如何创建的代理,最后加入了advisors

Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);

advisors前面已经说了,是切面,联合切点和通知的地方,所以上面的代码就是将切点放进切面当中!

至此,spring 自动代理bean大概的脉络就清晰了,切面连接切点就通了。至于切面和通知是怎么处理到一起的?
还是回到AbstractAutoProxyCreator.java中来,看到这里有个getAdvicesAndAdvisorsForBean方法,进入他的子类看看是怎么实现的:

@Override
    protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
        List advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
    }

进入findEligibleAdvisors看看是怎么织入的

/**
     * Find all eligible Advisors for auto-proxying this class.
     * @param beanClass the clazz to find advisors for
     * @param beanName the name of the currently proxied bean
     * @return the empty List, not <code>null</code>,
     * if there are no pointcuts or interceptors
     * @see #findCandidateAdvisors
     * @see #sortAdvisors
     * @see #extendAdvisors
     */
    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;
    }

没什么收获,进入findCandidateAdvisors看看,就在该方法下面,在进入findAdvisorBeans:

/** * 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 = null;
        synchronized (this) {
            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 LinkedList<Advisor>();
        }

        List<Advisor> advisors = new LinkedList<Advisor>();
        for (String name : advisorNames) {
            if (isEligibleBean(name) && !this.beanFactory.isCurrentlyInCreation(name)) {
                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("Ignoring currently created advisor '" + name + "': " + 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;
    }

一大堆不知道怎么看,分点看即可:

(1)获取advisorNames,看看有没有合适的EligibleBean
(2)遍历advisorNames,将bean加入advisor(通知+切面)

至此就完了,很简单的流程,绕来绕去我自己也看不太懂,没法画流程图,也不知道是谁执行的aop,这方便以后有时间再慢慢看。

    原文作者:AOP
    原文地址: https://blog.csdn.net/change_on/article/details/80097411
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞