Spring AOP源码分析

AOP基本概述

Advice(通知)

  • BeforeAdvice
package org.springframework.aop;

import java.lang.reflect.Method;

public interface MethodBeforeAdvice extends BeforeAdvice {

    void before(Method method, Object[] args, Object target) throws Throwable;

}

before是回调方法,在Advice中配置了目标方法后,会在调用目标方法时被回调。

参数:

method:目标方法

args:目标方法的输入参数

target:目标对象

  • AfterReturningAdvice
package org.springframework.aop;

import java.lang.reflect.Method;

public interface AfterReturningAdvice extends AfterAdvice {
    void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;

}

在目标方法调用结束并正常返回时,接口被回调

  • ThrowsAdvice
public interface ThrowsAdvice extends AfterAdvice {

}

抛出异常时被回调,AOP使用反射实现(方法名叫AfterThrowing?)

PointCut(切入点)

public interface Pointcut {

    ClassFilter getClassFilter();

    MethodMatcher getMethodMatcher();

    Pointcut TRUE = TruePointcut.INSTANCE;
}

PointCut是通过MethodMatcher 进行切入点方法匹配的,判断是否需要对当前方法进行增强处理。

通过JdkRegexpMethodPointcut理解MethodMatcher:

在JdkRegexpMethodPointcut的基类StaticMethodMatcherPointcut中设置MethodMatcher为StaticMethodMatcherPointcut(StaticMethodMatcher)

public abstract class StaticMethodMatcherPointcut extends StaticMethodMatcher implements Pointcut {
    @Override
    public final MethodMatcher getMethodMatcher() {
        return this;
    }
}

在JdkRegexpMethodPointcut中通过正则表达式匹配需要增强的方法:

protected boolean matches(String pattern, int patternIndex) {
    Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
    return matcher.matches();
}

在NameMatchMethodPointcut中通过方法名进行方法的匹配:

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

protected boolean isMatch(String methodName, String mappedName) {
    return PatternMatchUtils.simpleMatch(mappedName, methodName);
}

Advisor(通知器)

通知器负责把切入点和增强处理接合起来。

在切点处决定使用哪个通知

AOP设计与实现

JVM动态代理

JDK和CGLIB都是用动态代理实现的

AopProxy代理对象

Spring中,是通过ProxyFactoryBean来完成代理对象的生成的

  • ProxyConfig

数据基类,为ProxyFactoryBean这样的子类提供配置属性。

  • AdvisedSupport

AOP对通知和通知器的操作,对不同的AOP代理的生成都是一样的。对于具体生代理类,由AdvisedSupport的子类来做。

  • ProxyCreatorSupport

子类创建AOP代理类的辅助

  • ProxyFactoryBean

IOC容器中声明式配置,生成代理类

  • ProxyFactory

编程式使用,生成代理类

  • AspectJProxyFactory

需要使用AspectJ功能的AOP应用,这个起到集成Spring和AspectJ的作用

具体AOP代理对象的生成是由ProxyFactoryBean、ProxyFactory、AspectJProxyFactory完成的。

如何配置ProxyFactory?

<bean id="testAdvisor" class="com.abc.TestAdvisor" />
<!-- 通知器,实现了目标对象需要增强的切面行为,也就是通知 -->
<bean id="testAop" class="org.springframework.aop.ProxyFactoryBean">
    <property name="proxyInterfaces">
        <value>com.test.AbcInterface</value>
    </property>
    <property name="target">
        <!-- 目标对象 -->
        <bean class="com.abc.TestTarget" />
    </property>
    <property name="interceptorNames">
        <!-- 需要拦截的方法接口,通知器 -->
        <list>
            <value>
                testAdvisor
            </value>
        </list>
    </property>
</bean>

代理对象获取入口:

ProxyFactoryBean的getObject

AopProxy生成过程:

ProxyFactoryBean的getObject获取代理对象

@Override
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();
    }
}

关于initializeAdvisorChain

这个初始化过程有一个标志位advisorChainInitialized,这个标志用来表示通知器链是否已经初始化。

如果已经初始化,那么这里不会再初始化,直接返回。初始化只是在应用第一次通过ProxyFactoryBean获取代理对象的时候。

完成这个初始化之后,接着会读取配置中出现的所有通知器(把通知器的名字交给容器的getBean,IOC容器的回调获取通知器),把通知器加入拦截器链(addAdvisoronChainCreation实现)。

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

        // Globals can‘t be last unless we specified a targetSource using the property...
        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");
        }

        // Materialize interceptor chain from bean names.
        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 {
                // If we get here, we need to add a named interceptor.
                // We must check if it‘s a singleton or prototype.
                Object advice;
                if (this.singleton || this.beanFactory.isSingleton(name)) {
                    // Add the real Advisor/Advice to the chain.
                    advice = this.beanFactory.getBean(name);
                }
                else {
                    // It‘s a prototype Advice or Advisor: replace with a prototype.
                    // Avoid unnecessary creation of prototype bean just for advisor chain initialization.
                    advice = new PrototypePlaceholderAdvisor(name);
                }
                addAdvisorOnChainCreation(advice, name);
            }
        }
    }

    this.advisorChainInitialized = true;
}

生成单件代理对象

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));
        }
        // Initialize the shared singleton instance.
        super.setFrozen(this.freezeProxy);
        //这里方法会使用ProxyFactory生成需要的Proxy
        this.singletonInstance = getProxy(createAopProxy());
    }
    return this.singletonInstance;
}

//通过createAopProxy返回的AopProxy来得到代理对象
protected Object getProxy(AopProxy aopProxy) {
    return aopProxy.getProxy(this.proxyClassLoader);
}

具体代理对象的生成,是在ProxyFactoryBean的基类AdvisedSupport的实现中借助AopProxyFactory完成。

在ProxyCreatorSupport中,AopProxy是通过AopProxyFactory生成的,需要生成的代理对象信息封装在AdvisedSupport中,这个对象也是createAopProxy的输入参数(this):

protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        activate();
    }
    //通过AopProxyFactory取得AopProxy,AopProxyFactory是在初始化函数中定义的,使用的是DefaultAopProxyFactory
    return getAopProxyFactory().createAopProxy(this);
}

现在问题转换为DefaultAopProxyFactory如何生成AopProxy了,这里有两种方式,JdkDynamicAopProxy和CglibProxyFactory

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            //获取配置的目标对象
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
            //如果没有目标对象,抛出异常,提醒AOP应用提供正确的目标配置
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            //由于CGLIB是一个第三方类库,所以需要在CLASSPATH中配置
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }
}

JdkDynamicAopProxy 生成AopProxy代理对象:

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
    @Override
    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);

        //JdkDynamicAopProxy 需要实现InvocationHandler这里才能传this
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //...代理的回调方法,invoke
    //也可以理解为拦截方法

    }
}

CglibProxyFactory生成AopProxy代理对象:

@Override
public Object getProxy(ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
    }

    try {
        Class<?> rootClass = this.advised.getTargetClass();
        Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

        Class<?> proxySuperClass = rootClass;
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            proxySuperClass = rootClass.getSuperclass();
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            for (Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }

        // Validate the class, writing log messages as necessary.
        validateClassIfNecessary(proxySuperClass, classLoader);

        // Configure CGLIB Enhancer...
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader &&
                    ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }
        enhancer.setSuperclass(proxySuperClass);
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

        Callback[] callbacks = getCallbacks(rootClass);
        Class<?>[] types = new Class<?>[callbacks.length];
        for (int x = 0; x < types.length; x++) {
            types[x] = callbacks[x].getClass();
        }
        // fixedInterceptorMap only populated at this point, after getCallbacks call above
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);

        // Generate the proxy class and create a proxy instance.
        return createProxyClassAndInstance(enhancer, callbacks);
    }
    catch (CodeGenerationException ex) {
        throw new AopConfigException("Could not generate CGLIB subclass of class [" +
                this.advised.getTargetClass() + "]: " +
                "Common causes of this problem include using a final class or a non-visible class",
                ex);
    }
    catch (IllegalArgumentException ex) {
        throw new AopConfigException("Could not generate CGLIB subclass of class [" +
                this.advised.getTargetClass() + "]: " +
                "Common causes of this problem include using a final class or a non-visible class",
                ex);
    }
    catch (Exception ex) {
        // TargetSource.getTarget() failed
        throw new AopConfigException("Unexpected AOP exception", ex);
    }
}

拦截方法写在内部类里了(在上面getCallbacks涉及到):

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

    private final AdvisedSupport advised;

    public DynamicAdvisedInterceptor(AdvisedSupport advised) {
        this.advised = advised;
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;
        Class<?> targetClass = null;
        Object target = null;
        try {
            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
            // May be null. Get as late as possible to minimize the time we
            // "own" the target, in case it comes from a pool...
            target = getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            Object retVal;
            // Check whether we only have one InvokerInterceptor: that is,
            // no real advice, but just reflective invocation of the target.
            if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                // We can skip creating a MethodInvocation: just invoke the target directly.
                // Note that the final invoker must be an InvokerInterceptor, so we know
                // it does nothing but a reflective operation on the target, and no hot
                // swapping or fancy proxying.
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = methodProxy.invoke(target, argsToUse);
            }
            else {
                // We need to create a method invocation...
                retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
            }
            retVal = processReturnType(proxy, target, method, retVal);
            return retVal;
        }
        finally {
            if (target != null) {
                releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

    @Override
    public boolean equals(Object other) {
        return (this == other ||
                (other instanceof DynamicAdvisedInterceptor &&
                        this.advised.equals(((DynamicAdvisedInterceptor) other).advised)));
    }

    /**
     * CGLIB uses this to drive proxy creation.
     */
    @Override
    public int hashCode() {
        return this.advised.hashCode();
    }

    protected Object getTarget() throws Exception {
        return this.advised.getTargetSource().getTarget();
    }

    protected void releaseTarget(Object target) throws Exception {
        this.advised.getTargetSource().releaseTarget(target);
    }
}

可以把AOP的实现部分堪称有基础设施准备和AOP运行辅助这两部分组成。

这里的AOPProxy代理对象的生成,可以看作是一个静态的AOP基础设施的建立过程。通过这个准备过程,把代理对象、拦截器这些待调用的部分都准备好,等待着AOP运行过程中对这些基础设施的使用。

对于应用触发的AOP应用,会涉及AOP框架的运行和对AOP基础设施的使用。

这些动态的运行部分,是从拦截器回调入口开始的。

时间: 2024-10-26 20:41:04

Spring AOP源码分析的相关文章

曹工说Spring Boot源码(18)-- Spring AOP源码分析三部曲,终于快讲完了 (aop:config完整解析【下】)

写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解 曹工说Spring Boot源码(3)-- 手动注册Bean Definition不比游戏好玩吗,我们来试一下 曹工说Spring Boot源码(4)-- 我是怎么自定义ApplicationContext,从json文件读取bean de

Spring AOP源码分析(拦截器调用的实现)

在Spring AOP通过JDK或者Cglib的方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中的作用是通过对这些方法的回调完成的. JdkDynamicAopProxy的invoke拦截 JdkDynamicAopProxy的invoke @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation in

spring事务源码分析结合mybatis源码(一)

最近想提升,苦逼程序猿,想了想还是拿最熟悉,之前也一直想看但没看的spring源码来看吧,正好最近在弄事务这部分的东西,就看了下,同时写下随笔记录下,以备后查. spring tx源码分析 这里只分析简单事务也就是DataSourceTransactionManager 首先肯定找入口了,看过spring源码的同学一定都会找spring tx的入口就是在TxAdviceBeanDefinitionParser这里将解析tx的配置,生成TransactionInterceptor对象,这个也就是一

Spring IoC 源码分析 (基于注解) 之 包扫描

在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫描的过滤规则.那我们今天就来看下包扫描的具体过程. 还是先看下面的代码: AnnotationConfigApplicationContext类 //该构造函数会自动扫描以给定的包及其子包下的所有类,并自动识别所有的Spring Bean,将其注册到容器中 public AnnotationConf

Spring AMQP 源码分析 05 - 异常处理

### 准备 ## 目标 了解 Spring AMQP Message Listener 如何处理异常 ## 前置知识 <Spring AMQP 源码分析 04 - MessageListener> ## 相关资源 Offical doc:<http://docs.spring.io/spring-amqp/docs/1.7.3.RELEASE/reference/html/_reference.html#exception-handling> Sample code:<ht

Spring AMQP 源码分析 07 - MessageListenerAdapter

### 准备 ## 目标 了解 Spring AMQP 如何用 POJO 处理消息 ## 前置知识 <Spring AMQP 源码分析 04 - MessageListener> ## 相关资源 Offical doc:<http://docs.spring.io/spring-amqp/docs/1.7.3.RELEASE/reference/html/_reference.html#message-listener-adapter> Sample code:<https:

Spring AMQP 源码分析 06 - 手动消息确认

### 准备 ## 目标 了解 Spring AMQP 如何手动确认消息已成功消费 ## 前置知识 <Spring AMQP 源码分析 04 - MessageListener> ## 相关资源 Offical doc:<http://docs.spring.io/spring-amqp/docs/1.7.3.RELEASE/reference/html/_reference.html#message-listener-adapter> Sample code:<https:

Spring AMQP 源码分析 08 - XML 配置

### 准备 ## 目标 通过 XML 配置文件使用 Spring AMQP ## 前置知识 <Spring AMQP 源码分析 07 - MessageListenerAdapter> ## 相关资源 Sample code:<https://github.com/gordonklg/study>,rabbitmq module 源码版本:Spring AMQP 1.7.3.RELEASE ## 测试代码 gordon.study.rabbitmq.springamqp.XmlC

做一个合格的程序猿之浅析Spring AOP源码(十八) Spring AOP开发大作战源码解析

其实上一篇文章价值很小,也有重复造轮子的嫌疑,网上AOP的实例很多,不胜枚举,其实我要说的并不是这个,我想要说的就是上一节中spring的配置文件: 我们这边并没有用到我们上几节分析的哪几个AOP的主要实现类:ProxyFactoryBean.java , ProxyFactory.java ,AspectJProxyFactory.java ,在我们这个配置文件中,根本没有显示的去配置这些类,那么spring到底是怎么做到的呢? 大家可以这么想,spring到底是怎么去杀害目标对象的呢?真正的