懂 Spring AOP 源码

纵然是瞬间 提交于 2021-02-18 14:25:30

1 主要的接口

1.1 Advice 通知

本接口定义了切面的增强方式,如:前置增强 BeforeAdvice,后置增强 AfterAdvice,异常增强 ThrowsAdvice 等。下面看两个主要的子接口的源码。

public interface MethodBeforeAdvice extends BeforeAdvice {    /**     * 目标方法 method 开始执行前,AOP 会回调此方法     */    void before(Method method, Object[] args, Object target) throws Throwable;}public interface AfterReturningAdvice extends AfterAdvice {    /**     * 目标方法 method 执行后,AOP 会回调此方法,注意,它还传入了 method 的返回值     */    void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;}

1.2 Pointcut 方法的横切面

本接口用来定义需要增强的目标方法的集合,一般使用正则表达式去匹配筛选指定范围内的所有满足条件的目标方法。Pointcut 接口有很多实现,我们主要看一下 JdkRegexpMethodPointcut 和 NameMatchMethodPointcut 的实现原理,前者主要通过正则表达式对方法名进行匹配,后者则通过匹配方法名进行匹配。

    // JdkRegexpMethodPointcut 的实现源码    private Pattern[] compiledPatterns = new Pattern[0];    protected boolean matches(String pattern, int patternIndex) {        Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);        return matcher.matches();    }    // NameMatchMethodPointcut 的实现源码    private List<String> mappedNames = new LinkedList<String>();    public boolean matches(Method method, Class targetClass) {        for (String mappedName : this.mappedNames) {            if (mappedName.equals(method.getName()) || isMatch(method.getName(), mappedName)) {                return true;            }        }        return false;    }

1.3 Advisor 通知器

将 Pointcut 和 Advice 有效地结合在一起。它定义了在哪些方法(Pointcut)上执行哪些动作(Advice)。下面看一下 DefaultPointcutAdvisor 的源码实现,它通过持有 Pointcut 和 Advice 属性来将两者有效地结合在一起。

public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {    private Pointcut pointcut = Pointcut.TRUE;    public DefaultPointcutAdvisor() {    }    public DefaultPointcutAdvisor(Advice advice) {        this(Pointcut.TRUE, advice);    }    /**     * 自己定义了 Pointcut属性,而 Advice属性 则使用父类中的定义     */    public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {        this.pointcut = pointcut;        setAdvice(advice);    }}public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor {    //本类是一个抽象类,其持有 Advice 的引用,而对 Pointcut 的引用,则在具体的子类中持有    private Advice advice;    public void setAdvice(Advice advice) {        this.advice = advice;    }    public Advice getAdvice() {        return this.advice;    }    @Override    public String toString() {        return getClass().getName() + ": advice [" + getAdvice() + "]";    }}

2 Spring AOP 的设计与实现

AOP 的实现代码中,主要使用了 JDK 动态代理,在特定场景下(被代理对象没有 implements 的接口)也用到了 CGLIB 生成代理对象。通过 AOP 的源码设计可以看到,其先为目标对象建立了代理对象,这个代理对象的生成可以使用 JDK 动态代理或 CGLIB 完成。然后启动为代理对象配置的拦截器,对横切面(目标方法集合)进行相应的增强,将 AOP 的横切面设计和 Proxy 模式有机地结合起来,实现了在 AOP 中定义好的各种织入方式。

2.1 ProxyFactoryBean

这里我们主要以 ProxyFactoryBean 的实现为例,对 AOP 的实现原理进行分析。ProxyFactoryBean 主要持有目标对象 target 的代理对象 aopProxy,和 Advisor 通知器,而 Advisor 持有 Advice 和 Pointcut,这样就可以判断 aopProxy 中的方法 是否是某个指定的切面 Pointcut,然后根据其配置的织入方向(前置增强/后置增强),通过反射为其织入相应的增强行为 Advice。先看一下 ProxyFactoryBean 的配置和使用。

<!-- 定义自己的 Advisor 实现,其中包含了 Pointcut 和 Advice --><bean id="myAdvisor" class="com.shuitu.MyAdvisor"/><bean id="myAOP" class="org.springframework.aop.framework.ProxyFactoryBean">    <!-- 代理类实现的接口 -->    <property name="proxyInterface"><value>com.shuitu.ProxyInterface</value></property>    <!-- 被代理的对象 -->    <property name="target">        <bean class="com.shuitu.MyTarget"/>    </property>    <!-- 配置相应的 Advisor -->    <property name="interceptorNames">        <list><value>myAdvisor</value></list>    </property></bean>

2.2 为配置的 target 生成 AopProxy 代理对象

ProxyFactoryBean 的 getObject() 方法先对通知器链进行了初始化,然后根据被代理对象类型的不同,生成代理对象。

    /**     * 返回一个代理对象,当用户从 FactoryBean 中获取 bean 时调用,     * 创建此工厂要返回的 AOP 代理的实例,该实例将作为一个单例被缓存     */    public Object getObject() throws BeansException {        // 初始化通知器链        initializeAdvisorChain();        // 这里对 Singleton 和 prototype 的类型进行区分,生成对应的 proxy        if (isSingleton()) {            return getSingletonInstance();        }        else {            if (this.targetName == null) {                logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +                        "Enable prototype proxies by setting the 'targetName' property.");            }            return newPrototypeInstance();        }    }

2.3 初始化 Advisor 链

    /**     * 初始化 Advisor 链,可以发现,其中有通过对 IoC 容器的 getBean() 方法的调用来获取配置好的 advisor 通知器     */    private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {        // 如果通知器链已经完成初始化,则直接返回        if (this.advisorChainInitialized) {            return;        }        if (!ObjectUtils.isEmpty(this.interceptorNames)) {            if (this.beanFactory == null) {                throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +                        "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));            }            if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&                    this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {                throw new AopConfigException("Target required after globals");            }            // 这里添加了 Advisor 链的调用,下面的 interceptorNames 是在配置文件中            // 通过 interceptorNames 进行配置的。由于每一个 Advisor 都是被配置为 bean 的,            // 所以通过遍历 interceptorNames 得到的 name,其实就是 bean 的 id,通过这个 name(id)            // 我们就可以从 IoC 容器中获取对应的实例化 bean            for (String name : this.interceptorNames) {                if (logger.isTraceEnabled()) {                    logger.trace("Configuring advisor or advice '" + name + "'");                }                if (name.endsWith(GLOBAL_SUFFIX)) {                    if (!(this.beanFactory instanceof ListableBeanFactory)) {                        throw new AopConfigException(                                "Can only use global advisors or interceptors with a ListableBeanFactory");                    }                    addGlobalAdvisor((ListableBeanFactory) this.beanFactory,                            name.substring(0, name.length() - GLOBAL_SUFFIX.length()));                }                else {                    // 对当前的 factoryBean 进行类型判断,是属于单例 bean 还是原型 bean                    Object advice;                    if (this.singleton || this.beanFactory.isSingleton(name)) {                        // 通过 beanFactory 的 getBean() 方法获取 advisor,                        // 这个 name 是从 interceptorNames 中获取的                        advice = this.beanFactory.getBean(name);                    }                    else {                        // 如果是原型 bean                        advice = new PrototypePlaceholderAdvisor(name);                    }                    addAdvisorOnChainCreation(advice, name);                }            }        }        this.advisorChainInitialized = true;    }

生成 singleton 的代理对象在 getSingletonInstance 方法中完成,这是 ProxyFactoryBean 生成 AopProxy 代理对象的调用入口。代理对象会封装对 target 对象的调用,针对 target 对象的方法调用会被这里生成的代理对象所拦截。

2.4 生成单例代理对象

    /**     * 返回此类代理对象的单例实例,如果尚未创建该实例,则单例地创建它     */    private synchronized Object getSingletonInstance() {        if (this.singletonInstance == null) {            this.targetSource = freshTargetSource();            if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {                // 根据 AOP 框架来判断需要代理的接口                Class targetClass = getTargetClass();                if (targetClass == null) {                    throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");                }                // 设置代理对象的接口                setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));            }            super.setFrozen(this.freezeProxy);            // 这里会通过 AopProxy 来得到代理对象            this.singletonInstance = getProxy(createAopProxy());        }        return this.singletonInstance;    }    /**     * 通过 createAopProxy()方法 返回的 aopProxy 获取代理对象     */    protected Object getProxy(AopProxy aopProxy) {        return aopProxy.getProxy(this.proxyClassLoader);    }

上面的 createAopProxy() 方法,调用了 ProxyFactoryBean 的父类 ProxyCreatorSupport 中的实现。

public class ProxyCreatorSupport extends AdvisedSupport {    private AopProxyFactory aopProxyFactory;    public ProxyCreatorSupport() {        // 注意这里实例化的是一个 DefaultAopProxyFactory,所以下面的 createAopProxy() 方法        // 中调用的也是 DefaultAopProxyFactory 的实现        this.aopProxyFactory = new DefaultAopProxyFactory();    }    protected final synchronized AopProxy createAopProxy() {        if (!this.active) {            activate();        }        //调用的是 DefaultAopProxyFactory 的实现        return getAopProxyFactory().createAopProxy(this);    }    public AopProxyFactory getAopProxyFactory() {        return this.aopProxyFactory;    }    public AopProxyFactory getAopProxyFactory() {        return this.aopProxyFactory;    }}

下面看一下 AopProxyFactory 接口的实现类 DefaultAopProxyFactory 的 createAopProxy(AdvisedSupport config)方法。

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {        // AopProxy 代理对象的生成过程:        // 首先从 AdvisedSupport 对象中获取配置的 target 目标对象的类型 targetClass,        // 然后根据 targetClass 是否为接口采取不同的生成代理对象的策略        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.");            }            /**             * !!!!!!!!!!!!!!!!!!!!!!!!!!             * 如果目标类是接口,则使用 JDK 动态代理,否则使用 CGLIB             * !!!!!!!!!!!!!!!!!!!!!!!!!!             */            if (targetClass.isInterface()) {                return new JdkDynamicAopProxy(config);            }            return CglibProxyFactory.createCglibProxy(config);        }        else {            return new JdkDynamicAopProxy(config);        }    }

可以看到其根据目标对象是否实现了接口,而决定是使用 JDK 动态代理 还是 CGLIB 去生成代理对象,而 AopProxy 接口的实现类也只有 JdkDynamicAopProxy 和 CglibAopProxy 这两个。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!