重拾-Spring-AOP

栏目: Java · 发布时间: 5年前

内容简介:关于 AOP 的概念描述及相关术语可以参考接口实现类如下:执行结果如下:

AOP 术语

关于 AOP 的概念描述及相关术语可以参考 彻底征服 Spring AOP 之 理论篇 总结的很好; 本文将着重分析下 AOP 的实现过程。

使用示例

定义接口

public interface UserService {
    void say ();
}

接口实现类如下:

public class UserServiceImpl implements UserService {
    public void say() {
        System.out.println("do say method");
    }
}

定义通知

public class UserAdvice implements MethodBeforeAdvice {

    public void before(Method m, Object[] args, Object target) throws Throwable {
        System.out.println("do before advice ....");
    }
}

配置 AOP

<beans>
    <!-- 配置接口实现类 -->
    <bean id="userService" class="org.springframework.aop.UserServiceImpl" />

    <!-- 配置通知类 -->
    <bean id="userAdvice" class="org.springframework.aop.UserAdvice" />

    <!--代理类-->
    <bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--要代理的接口 创建代理对象时需要-->
        <!-- 配置该属性会采用 jdk 动态代理,反之采用 cglib -->
        <property name="proxyInterfaces">
            <value>org.springframework.aop.UserService</value>
        </property>
        <!--拦截器名字,也就是我们定义的通知类,可配置多个通知类 -->
        <property name="interceptorNames">
            <list>
                <value>userAdvice</value>
            </list>
        </property>
        <!--目标类,就是我们业务的实现类-->
        <property name="target">
            <ref bean="userService"/>
        </property>
    </bean>
</beans>

测试

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/org/springframework/aop/aop.xml");

UserService userService = (UserService) ctx.getBean("userProxy");

userService.say();

执行结果如下:

do before advice ....
do say method

从执行结果来看,前置通知对接口方法已经起增强作用。 下面我们将看下 Spring AOP 的具体实现。

实现分析

从上面的示例可以看出 Spring AOP 的配置主要基于类 ProxyFactoryBean ,那么我们就以此为入口去剖析其实现。

ProxyFactoryBean 类结构

重拾-Spring-AOP

创建切面链

ProxyFactoryBean 的类结构,我们发现其实现了接口 BeanFactoryAware ,也就说明在其实例化过程中会调用方法 setBeanFactory ; 源码如下:

public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    // 设置 beanFactory
    this.beanFactory = beanFactory;
    logger.debug("Set BeanFactory. Will configure interceptor beans...");
    // 创建 advisor chain
    createAdvisorChain();
    logger.info("ProxyFactoryBean config: " + this);
    if (singleton) {
        // Eagerly initialize the shared singleton instance
        getSingletonInstance();
        // We must listen to superclass advice change events to recache singleton
        // instance if necessary
        addListener(this);
    }
}

setBeanFactory 方法中除了设置 beanFactory , 还有一个重要的动作就是 createAdvisorChain 创建 advisor chain (也可以理解为就是切面链)。 那么下面我们将看下具体是怎样创建 advisor chain 的。

private void createAdvisorChain() throws AopConfigException, BeansException {
    // 检测是否配置了 interceptorNames, 也就是是否配置相关 advice 通知; 若没有配置直接返回
    if (this.interceptorNames == null || this.interceptorNames.length == 0) {
        //throw new AopConfigException("Interceptor names are required");
        return;
    }
    
    // Globals can't be last
    if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX)) {
        throw new AopConfigException("Target required after globals");
    }

    // Materialize interceptor chain from bean names
    for (int i = 0; i < this.interceptorNames.length; i++) {
        String name = this.interceptorNames[i];
        logger.debug("Configuring interceptor '" + name + "'");
        // 判断 interceptor name 是否以 * 结尾
        if (name.endsWith(GLOBAL_SUFFIX)) {
            if (!(this.beanFactory instanceof ListableBeanFactory)) {
                throw new AopConfigException("Can only use global advisors or interceptors with a ListableBeanFactory");
            }
            else {
                addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
                                 name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
            }
        }
        else {
            // add a named interceptor
            // 获取 advice bean
            Object advice = this.beanFactory.getBean(this.interceptorNames[i]);
            // 将 advisor 加入到链表中
            addAdvisor(advice, this.interceptorNames[i]);
        }
    }
}
private void addAdvisor(Object next, String name) {
    logger.debug("Adding advisor or TargetSource [" + next + "] with name [" + name + "]");
    // We need to add a method pointcut so that our source reference matches
    // what we find from superclass interceptors.
    // 查找 advice 通知匹配的 pointcut, 并创建一个 advisor
    Object advisor = namedBeanToAdvisorOrTargetSource(next);
    if (advisor instanceof Advisor) {
        // if it wasn't just updating the TargetSource
        logger.debug("Adding advisor with name [" + name + "]");
        addAdvisor((Advisor) advisor);
        this.sourceMap.put(advisor, name);
    }
    else {
        logger.debug("Adding TargetSource [" + advisor + "] with name [" + name + "]");
        setTargetSource((TargetSource) advisor);
        // save target name
        this.targetName = name;
    }
}

addAdvisor 方法可以看到,在添加 advisor 前,需要先创建 advisor , 会调用方法 namedBeanToAdvisorOrTargetSource

private Object namedBeanToAdvisorOrTargetSource(Object next) {
    try {
        // 将 advice 包装成一个 advisor
        Advisor adv = GlobalAdvisorAdapterRegistry.getInstance().wrap(next);
        return adv;
    }
    catch (UnknownAdviceTypeException ex) {
        
    }
}

namedBeanToAdvisorOrTargetSource 方法会调用单例模式的 GlobalAdvisorAdapterRegistry 的方法 wrap 将 advice 包装成一个 advisor;

在查看 wrap 的实现之前,我们可以先看下 GlobalAdvisorAdapterRegistry 是做什么的。

public class GlobalAdvisorAdapterRegistry extends DefaultAdvisorAdapterRegistry {
    
    private static GlobalAdvisorAdapterRegistry instance = new GlobalAdvisorAdapterRegistry();
    
    public static GlobalAdvisorAdapterRegistry getInstance() {
        return instance;
    }

    private GlobalAdvisorAdapterRegistry() {
    }    
}

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry {
    
    private List adapters = new LinkedList();
    
    public DefaultAdvisorAdapterRegistry() {
        // register well-known adapters
        registerAdvisorAdapter(new BeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }
}

从上面 GlobalAdvisorAdapterRegistry 的实现可以看出其采用了单例模式并继承了类 DefaultAdvisorAdapterRegistry 在构造的过程中内置了 3 种 advice adapter 用于匹配 advice 。 下面我们在看下它是如何 wrap 包装 advice 的。

public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
    if (adviceObject instanceof Advisor) {
        return (Advisor) adviceObject;
    }
    
    if (!(adviceObject instanceof Advice)) {
        throw new UnknownAdviceTypeException(adviceObject);
    }
    Advice advice = (Advice) adviceObject;
    
    if (advice instanceof Interceptor) {
        // So well-known it doesn't even need an adapter
        return new DefaultPointcutAdvisor(advice);
    }

    // 遍历内置的 advice adapters
    for (int i = 0; i < this.adapters.size(); i++) {
        // Check that it is supported
        AdvisorAdapter adapter = (AdvisorAdapter) this.adapters.get(i);
        // 判断当前 adapter 是否支付当前 advice
        if (adapter.supportsAdvice(advice)) {
            // 如果支持的话,返回一个 DefaultPointcutAdvisor
            return new DefaultPointcutAdvisor(advice);
        }
    }
    throw new UnknownAdviceTypeException(advice);
}

wrap 的实现可以发现,若 advice 匹配了某个 adapter 将会创建一个 DefaultPointcutAdvisor 实例并返回;

public class DefaultPointcutAdvisor implements PointcutAdvisor, Ordered {

    private int order = Integer.MAX_VALUE;

    private Pointcut pointcut;
    
    private Advice advice;
    
    public DefaultPointcutAdvisor() {
    }
    
    public DefaultPointcutAdvisor(Advice advice) {
        this(Pointcut.TRUE, advice);
    }
    
    public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
        this.pointcut = pointcut;
        this.advice = advice;
    }
}

/**
 * Canonical instance that matches everything.
 * 默认匹配所有的类及类下的所有方法
 */
Pointcut TRUE = new Pointcut() {

    public ClassFilter getClassFilter() {
        return ClassFilter.TRUE;
    }

    public MethodMatcher getMethodMatcher() {
        return MethodMatcher.TRUE;
    }

    public String toString() {
        return "Pointcut.TRUE";
    }
};

DefaultPointcutAdvisor 的实例可以看出创建 advisor (切面) 的过程实际就是将 advice (通知) 和 pointcut (切入点) 绑定的过程;同时在 Spring AOP 默认的 pointcut 是拦截所有类下的所有方法。

简单点说也就是当前切面将会拦截哪些类下的哪些方法,拦截过程中会采用哪些增强处理(前置通知,返回通知,异常通知)。

至此 advisor chain 的创建流程结束,其过程大概如下:

  • 遍历 interceptor names (也就是 advice 通知)
  • 获取 advice bean
  • 判断 advice 是否匹配内置的 advisorAdapter, 匹配的话则创建 DefaultPointcutAdvisor (默认拦截所有类所有方法) 加入到链表中

创建目标代理对象

ProxyFactoryBean 类的名字及类结构,发现其实现接口 FactoryBean , 也就是说当其 getBean 的时候会调用方法 getObject , 源码如下:

public Object getObject() throws BeansException {
    // 默认单例
    return (this.singleton) ? getSingletonInstance() : newPrototypeInstance();
}

private Object getSingletonInstance() {
    if (this.singletonInstance == null) {
        // This object can configure the proxy directly if it's
        // being used as a singleton.
        this.singletonInstance = createAopProxy().getProxy();
    }
    return this.singletonInstance;
}

protected synchronized AopProxy createAopProxy() {
    if (!isActive) {
        activate();
    }
    
    return getAopProxyFactory().createAopProxy(this);
}
public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
    // 是否采用 cglib 代理
    boolean useCglib = advisedSupport.getOptimize() || advisedSupport.getProxyTargetClass() || advisedSupport.getProxiedInterfaces().length == 0;
    if (useCglib) {
        return CglibProxyFactory.createCglibProxy(advisedSupport);
    }
    else {
        // Depends on whether we have expose proxy or frozen or static ts
        return new JdkDynamicAopProxy(advisedSupport);
    }
}
public Object getProxy(ClassLoader cl) {
    logger.debug("Creating JDK dynamic proxy");
    Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
    return Proxy.newProxyInstance(cl, proxiedInterfaces, this);
}

ProxyFactoryBean 通过判断 proxyTargetClass , interfaceNames 的配置去选择采用 cglib 或者 jdk 来创建目标代理对象。

目标代理对象执行

上面简单介绍了代理对象的创建,那么在看下当我们调用目标方法的时候,代理是如何执行的,以 jdk 动态代理为例:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    MethodInvocation invocation = null;
    Object oldProxy = null;
    boolean setProxyContext = false;

    TargetSource targetSource = advised.targetSource;
    Class targetClass = null;
    Object target = null;        
    
    try {
        // Try special rules for equals() method and implementation of the
        // Advised AOP configuration interface
        
        // Short-circuit expensive Method.equals() call, as Object.equals() isn't overloaded
        if (method.getDeclaringClass() == Object.class && "equals".equals(method.getName())) {
            // What if equals throws exception!?

            // This class implements the equals() method itself
            return new Boolean(equals(args[0]));
        }
        else if (Advised.class == method.getDeclaringClass()) {
            // Service invocations on ProxyConfig with the proxy config
            return AopProxyUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }
        
        Object retVal = null;
        
        // May be null. Get as late as possible to minimize the time we "own" the target,
        // in case it comes from a pool.
        // 目标实现类
        target = targetSource.getTarget();
        if (target != null) {
            targetClass = target.getClass();
        }
        
        if (this.advised.exposeProxy) {
            // Make invocation available if necessary
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
    
        // Get the interception chain for this method
        // 获取目标类,执行方法的 interception chain
        List chain = this.advised.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                this.advised, proxy, method, targetClass);
        
        // Check whether we have any advice. If we don't, we can fallback on
        // direct reflective invocation of the target, and avoid creating a MethodInvocation
        if (chain.isEmpty()) {
            // 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
            retVal = AopProxyUtils.invokeJoinpointUsingReflection(target, method, args);
        }
        else {
            
            invocation = new ReflectiveMethodInvocation(proxy, target,
                                method, args, targetClass, chain);
                                    
            // Proceed to the joinpoint through the interceptor chain
            // 方法调用
            retVal = invocation.proceed();
        }
        
        // Massage return value if necessary
        if (retVal != null && retVal == target) {
            retVal = proxy;
        }
        return retVal;
    }
    finally {
    }
}

首先我们看下如何获取匹配当前 method 的拦截器, 参考 calculateInterceptorsAndDynamicInterceptionAdvice 的实现如下:

public static List calculateInterceptorsAndDynamicInterceptionAdvice(Advised config, Object proxy, Method method, Class targetClass) {
    // 用于存储拦截器
    List interceptors = new ArrayList(config.getAdvisors().length);
    // 遍历 advisor (切面)
    for (int i = 0; i < config.getAdvisors().length; i++) {
        Advisor advisor = config.getAdvisors()[i];
        if (advisor instanceof PointcutAdvisor) {
            // Add it conditionally
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            // 判断当前 target class 是否当前 pointcut
            if (pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
                // 获取 advisor 对应的 method interceptor 
                MethodInterceptor interceptor = (MethodInterceptor) GlobalAdvisorAdapterRegistry.getInstance().getInterceptor(advisor);
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                // 判断当前 method 是否匹配 pointcut
                if (mm.matches(method, targetClass)) {
                    if (mm.isRuntime()) {
                        // Creating a new object instance in the getInterceptor() method
                        // isn't a problem as we normally cache created chains
                        interceptors.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm) );
                    }
                    else {                            
                        // 将拦截器加入链表中
                        interceptors.add(interceptor);
                    }
                }
            }
        }
        else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (ia.getClassFilter().matches(targetClass)) {
                MethodInterceptor interceptor = (MethodInterceptor) GlobalAdvisorAdapterRegistry.getInstance().getInterceptor(advisor);
                interceptors.add(interceptor);
            }
        }
    }    // for
    return interceptors;
}    // calculateInterceptorsAndDynamicInterceptionAdvice

我们在详细看下如何查找 advisor 匹配的拦截器呢,同样与上文中 wrap 类似,如下:

public Interceptor getInterceptor(Advisor advisor) throws UnknownAdviceTypeException {
    Advice advice = advisor.getAdvice();
    if (advice instanceof Interceptor) {
        return (Interceptor) advice;
    }

    // 遍历内置的 advisor adapter
    for (int i = 0; i < this.adapters.size(); i++) {
        AdvisorAdapter adapter = (AdvisorAdapter) this.adapters.get(i);
        // 是否匹配当前 advice
        if (adapter.supportsAdvice(advice)) {
            // 匹配的话返回 interceptor
            return adapter.getInterceptor(advisor);
        }
    }
    throw new UnknownAdviceTypeException(advisor.getAdvice());
}

到目前为止,我们多次发现 AdvisorAdapter 的身影,下面我们看下其具体的实现, 以 BeforeAdviceAdapter 为例:

class BeforeAdviceAdapter implements AdvisorAdapter {

    /**
     * @see org.springframework.aop.framework.adapter.AdvisorAdapter#supportsAdvice(java.lang.Object)
     */
    public boolean supportsAdvice(Advice advice) {
        // 匹配 MethodBeforeAdvice
        return advice instanceof MethodBeforeAdvice;
    }

    /**
     * @see org.springframework.aop.framework.adapter.AdvisorAdapter#getInterceptor(org.springframework.aop.Advisor)
     */
    public Interceptor getInterceptor(Advisor advisor) {
        MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
        // 返回 MethodBeforeAdviceInterceptor
        return new MethodBeforeAdviceInterceptor(advice) ;
    }

}

通过 AdvisorAdapter 很巧妙的将 Advice 和 Interceptor 结合起来,同时也会发现二者关系是一一对应的

下面在看下方法的真正调用过程, 由 ReflectiveMethodInvocation 的方法 proceed 实现:

public Object proceed() throws Throwable {
    //    We start with an index of -1 and increment early
    // 当执行到最后一个拦截器的时候将会调用目标方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    // 获取下一个拦截器
    Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        // Evaluate dynamic method matcher here: static part will already have
        // been evaluated and found to match
        InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            // Dynamic matching failed
            // Skip this interceptor and invoke the next in the chain
            return proceed();
        }
    }
    else {
        // It's an interceptor so we just invoke it: the pointcut will have
        // been evaluated statically before this object was constructed
        // 执行拦截器
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

下面具体看下 MethodInterceptor 的实现,分别是前置通知,返回通知,异常通知

public Object invoke(MethodInvocation mi) throws Throwable {
    // 目标方法前执行
    advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
    return mi.proceed();
}

public Object invoke(MethodInvocation mi) throws Throwable {
    // 先执行目标方法
    Object retval = mi.proceed();
    // 后置处理
    advice.afterReturning(retval, mi.getMethod(), mi.getArguments(), mi.getThis() );
    return retval;
}

public Object invoke(MethodInvocation mi) throws Throwable {
    try {
        // 执行目标方法
        return mi.proceed();
    }
    catch (Throwable t) {
        // 异常处理
        Method handlerMethod = getExceptionHandler(t);
        if (handlerMethod != null) {
            invokeHandlerMethod(mi, t, handlerMethod);
        }
        throw t;
    }
}

至此 Spring AOP 代理对象的执行过程处理结束,其流程可大概总结如下:

  • 获取当前目标方法的 interceptor chain

    1. 遍历 advisor ,判断当前目标类和目标方法是否匹配 advisor 对应的 ponitcut
    2. 通过匹配的 advisor 对应的 advice 匹配对应的 advisorAdapter , 进而获取对应的 methodInterceptor
  • 执行拦截器
  • 执行目标方法

小结

Spring AOP 中的对象关系小结下:

  • Advisor : 翻译是顾问,简单理解其就是一个 Aspect (切面); 其内部绑定了对应的 Pointcut(切入点) 和 Advice(通知)。
  • Advisor Chain : 切面链,是一系列的切面的集合。
  • Advice : 通知,是对拦截方法的增强处理;在 1.0 版本中包含 BeforeAdivce, AfterReturningAdvice, ThrowsAdvice; 其面向的是用户。
  • MethodInterceptor : 方法拦截器,是 Advice 的执行者; 与 Advice 是一一对应的。
  • AdvisorAdapter : Advice 的适配器,是 Advice 和 MethodInterceptor 匹配的纽带。
  • AdvisorAdapterRegistry : 是 AdvisorAdapter 的注册中心,内置了 BeforeAdviceAdapter, AfterReturnAdviceAdapter, ThrowsAdviceAdapter; 用来将 Advice wrap 成一个 Advisor 并提供获取 Advice 对应的 MethodInterceptor。

当我们自定义 Advice 时,可不可以同时支持多种 Advice 呢 ? 譬如:

public class UserAdvice implements MethodBeforeAdvice, AfterReturningAdvice {

    public void before(Method m, Object[] args, Object target) throws Throwable {
        System.out.println("do before advice ....");
    }

    public void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable {
        System.out.println("do after returning ....");
    }
}

那么当测试后,您会发现只有 before 调用了,而 afterReturning 未调用了;这是为什么呢 ? (好好看源码额)


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C Primer Plus(第6版)中文版

C Primer Plus(第6版)中文版

普拉达 (Stephen Prata) / 姜佑 / 人民邮电出版社 / 2016-4-1 / CNY 89.00

《C Primer Plus(第6版)中文版》详细讲解了C语言的基本概念和编程技巧。 《C Primer Plus(第6版)中文版》共17章。第1、2章介绍了C语言编程的预备知识。第3~15章详细讲解了C语言的相关知识,包括数据类型、格式化输入/输出、运算符、表达式、语句、循环、字符输入和输出、函数、数组和指针、字符和字符串函数、内存管理、文件输入输出、结构、位操作等。第16章、17章介绍C......一起来看看 《C Primer Plus(第6版)中文版》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

SHA 加密
SHA 加密

SHA 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具