Spring 核心之 AOP设计

AOP与Ioc是Spring的两大核心设计要素, 并且两者相辅相成, 共同构建起Spring的整个生态系统。

AOP 概述

AOP是Aspect-Oriented Programming (面向切面编程) 的简称, Aspect 是一种新的模块化机制, 它与面向对象(OOP)相补, OOP描述了对象自身的属性与行为, 再结合对象继承就能从纵向建立对象间的相互依赖与行为调用, 而AOP则从横向解决分散在不同业务对象中相同逻辑处理, 以获得业务过程中各部分间的低耦合性的隔离效果;

AOP概念介绍

Advice通知

Advice定义切点内容, 为切面增强提供织入接口。在Spring AOP中, 它主要描述围绕被切入方法调用而注入的切面行为。Advice是AOP中定义的一个接口(org.aopalliance.aop.Advice), 并且Spring为 AOP 切面增强 的织入做了更多的细化和扩展, 比如提供了更具体的通知类型, 如BeforeAdvice, AfterAdvice, ThrowAdvice等.

Pointcut切点

Pointcut决定Advice通知应该作用于哪个连接点, 也就是说通过Pointcut来定义需要增强的方法的集合, 这些集合的选取可以按照一定的规则来定义; 例如可以通过正则表达式进行标识, 或根据某类方法名进行匹配等.而在Pointcut的接口定义中可以看到, MethodMatcher对象可以通过正则表达式来匹配, NameMatchMethodPointcut可以通过比较方法名进行Advice的匹配;

Advisor通知器

完成对目标方法的切面增强设计(Advice)和关注点的设计(Pointcut)之后, 需要一个把二者结合到一起代理对象, 担当此角色的就是Advisor(通知器).

AOP 的设计

在jdk1.3版本里实现了动态代理模式, 加之立于Ioc容器的基石之上, Spring AOP的实现技术核心便是动态代理, 鉴于jdk原生的代理对象Proxy是使用反射的invoke方法实现的代理, 其性能比较差同时资源消耗也大, 因此可以采用三方类生成器CGLib来实现动态代理类的字节码生成;

AOP 的实现

建立AOPProxy代理对象

在Spring AOP模块中实现代理对象生成功能, 是由在生成与装配bean对象时调用ProxyFactoryBean来完成的;

接口设计继承图

继承图

相关接口与类的解释说明

(1). ProxyConfig: 为子类提供配置属性;
(2). Advised: 通知器的相关增删配置操作;
(3). AdvisedSupport: 辅助通知器配置类;
(4). ProxyCreatorSupport: 创建代理对象的辅助类;
(5). FactoryBean: 代理对象同样使用工厂方式管理
(6). AbstractSingletonProxyFactoryBean: 工厂方式管理单例代理对象;
(7). ProxyFactory: 在Spring里面编程式使用AOP功能
(8). AspectJProxyFactory: 结合Spring与AspectJ, 使用AspectJ的AOP功能;
(9). ProxyFactoryBean: 在Spring里, 通过在Ioc容器里进行声明式的配置实现AOP功能;
(10). TransactionProxyFactoryBean: Spring的事务就是通过AOP来实现的咯;

Spring AOP 拦截调用器的实现

设计原理

在Spring AOP通过JDK的Proxy方式或CGLib方式生成代理对象的时候, 相关的拦截器已经配置到代理对象中去了, 拦截器在代理对象中起作用是通过对这些方法的回调来完成的;

JdkDynamicAopProxy的invoke拦截

如下所示生成代理对象

Proxy.newProxyInstance(classLoader, A.getClass().getInterfaces(), B);
A: 需要被代理的类对象
B: 实现的InvocationHandler接口实例对象

在InvocationHandler里面的invoke方法是对JDK Proxy代理对象进行拦截时的回调入口,里面有获取目标对象, 拦截器链等, 在这个invoke方法中, 包含了完整的拦截器链对目标对象的拦截过程, 一步步完成拦截器的增强过程, 直至最后执行到目标对象方法的执行;

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

        TargetSource targetSource = this.advised.targetSource;
        Class<?> targetClass = null;
        Object target = null;

        try {
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                // The target does not implement the equals(Object) method itself.
                return equals(args[0]);
            }
            .....
            Object retVal;
            // 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();
            }

            // 获取指定方法对应的拦截链
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(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.
            // 执行拦截器与目标方法
            .....
            // 处理返回结果
            // Massage return value if necessary.
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                // Special case: it returned "this" and the return type of the method
                // is type-compatible. Note that we can't help if the target sets
                // a reference to itself in another returned object.
                retVal = proxy;
            }
            else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                throw new AopInvocationException(
                        "Null return value from advice does not match primitive return type for: " + method);
            }
            return retVal;
        }
        finally {
            //收尾工作
            if (target != null && !targetSource.isStatic()) {
                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

CGLib2AopProxy的intercept拦截

使用CglibAopProxy中的内部类DynamicAdvisedInterceptor作为通用回调处理类, 其中的intercept方法在执行时会构造CglibMethodInvocation对象来完成执行拦截器链的功能;

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

对目标方法进行调用

如果没有设置拦截器, 会对目标方法直接进行调用, 通过AopUtils使用发射机制在invokeJoinpointUsingReflection方法中实现;而对于CGLibAopProxy的代理对象, 它是通过目标对象调用CGLib的MethodProxy对象来直接完成的, 拦截功能已经是封装好的, 调用形式相对简单;

AOP拦截器链的调用

无论是上面JdkDynamicAopProxy的invoke, 还是CglibAopProxy中DynamicAdvisedInterceptor的intercept方法, 他们对AOP拦截器的处理都是大同小异的. 两者对拦截器的调用都是通过在ReflectiveMethodInvocation中通过proceed方法实现的. 在proceed方法中, 会逐个运行拦截器的拦截方法, 在执行单个拦截器前会进行matches方法调用进行匹配判断, 匹配才会执行拦截器, 不匹配继续递归执行proceed方法, 最终执行完所有拦截器并调用目标对象的实现方法进行返回.

public Object proceed() throws Throwable {
        //  We start with an index of -1 and increment early.
        // 从索引为-1的拦截器开始调用, 逐个递增, 如果拦截器调用玩了, 则执行目标对象方法;
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }
        // 这里沿着定义好的interceptorOrInterceptionAdvice链进行处理
        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.
            // 单单的一个Interceptor对象, 直接调用
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

配置通知器

下面逆序查看
(1). 执行时获取拦截器

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

(2). 使用AdvisedSupport进行获取

    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
        MethodCacheKey cacheKey = new MethodCacheKey(method);
        List<Object> cached = this.methodCache.get(cacheKey);
        if (cached == null) {
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                    this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }
        return cached;
    }

(3). 缓存中没有从默认的DefaultAdvisorChainFactory中加载

@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, Class<?> targetClass) {

    // This is somewhat tricky... We have to process introductions first,
    // but we need to preserve order in the ultimate list.
    // 到这里 Advised中的advisors是已经配置进去了的, 直接使用
    List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

    for (Advisor advisor : config.getAdvisors()) {
        // 切入点类型的通知器
        if (advisor instanceof PointcutAdvisor) {
            // Add it conditionally.
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                    // 判断这个方法匹配对象是否为动态的, 是的话需要在拦截器运行时判断执行
                    if (mm.isRuntime()) {
                        // Creating a new object instance in the getInterceptors() method
                        // isn't a problem as we normally cache created chains.
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    }
                    else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        // 执行多个AOP功能的高级接口
        else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        // 其他的类型通知器
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

(4). 在ProxyFactoryBean的getObject方法中对advisor进行初始化, 从XML配置中获取了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));
        }

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

Advice通知的实现

上面说了DefaultAdvisorChainFactory中的getInterceptorsAndDynamicInterceptionAdvice是获取Advisor chain的地方, 同时这里也隐藏着AOP实现的重要细节, 我们看GlobalAdvisorAdapterRegistry, 它本身只是一个简单的单例模式的应用, 而各种通知的适配和注册工作都是由它里面的DefaultAdvisorAdapterRegistry完成;

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {

    private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);


    /**
     * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
     * 默认加入三个适配器,为Spring AOP 提供编织能力
     */
    public DefaultAdvisorAdapterRegistry() {
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }


    @Override
    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 MethodInterceptor) {
            // So well-known it doesn't even need an adapter.
            return new DefaultPointcutAdvisor(advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            // Check that it is supported.
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }
        throw new UnknownAdviceTypeException(advice);
    }

    @Override
    // 把通知器转换为方法拦截器
    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
        Advice advice = advisor.getAdvice();
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
    }

    @Override
    public void registerAdvisorAdapter(AdvisorAdapter adapter) {
        this.adapters.add(adapter);
    }

}

这里举例分析下AfterReturningAdviceAdapter (在目标对象方法return后执行的拦截调用)

class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {

    @Override
    public boolean supportsAdvice(Advice advice) {
        return (advice instanceof AfterReturningAdvice);
    }

    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
        // 创建对应的方法拦截
        return new AfterReturningAdviceInterceptor(advice);
    }

}

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {

    private final AfterReturningAdvice advice;


    /**
     * Create a new AfterReturningAdviceInterceptor for the given advice.
     * @param advice the AfterReturningAdvice to wrap
     */
    public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }

    @Override
    //真正执行目标对象方法与AOP的Advice拦截执行的地方
    public Object invoke(MethodInvocation mi) throws Throwable {
        Object retVal = mi.proceed();
        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        return retVal;
    }

}

Spring AOP 的高级特性

  • HotSwappableTargetSource: 在运行时可以切换需要配置AOP功能的对象, 进行动态配置;

总结

在Spring的生态系统中, 通过对AOP的使用, 极大丰富了Spring框架的功能, 比如在各种驱动组件的实现上, 数据库事务, 日志系统埋点嵌入等都灵活运用了AOP的功能特性;

PS: 其他AOP功能操作示例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值