美文网首页
Spring 框架学习(四):AOP

Spring 框架学习(四):AOP

作者: albon | 来源:发表于2017-10-26 15:26 被阅读64次

    [TOC]

    Spring 框架学习(四):AOP

    概述

    AOP 是 Aspect Oriented Programming (面向切面编程)的简称,维基百科对 AOP 的描述如下:

    Aspect 是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点。从关注点中分离出横切关注点是面向切面的程序设计的核心概念。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑代码中不再含有针对特定领域问题代码的调用,业务领域同特定领域问题的关系通过切面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好地管理起来。

    由 AOP 联盟定义的 AOP 体系结构如下图所示:

    AOP 联盟定义的 AOP 体系结构

    AOP 体系结构分为从上到下、从使用到实现的三层结构。最高层是语言和开发环境,可以看到几个重要的概念:

    1. 基础,可以视为待增强对象,或者说目标对象。
    2. 切面,是对基础的增强应用。
    3. 配置,负责衔接基础和切面。把基础和切面结合起来,从而完成切面对目标对象的编织实现。

    第二个层次是为语言和开发环境提供支持的,在这个层次可以看到 AOP 框架的高层实现,主要包括配置和编织实现两部分内容。

    最底层是编织的具体实现模块,是为 AOP 提供技术支持的各种技术:反射、程序预处理、拦截器框架、元数据处理。

    对于 Spring 平台来说,AOP 是 Spring 框架的核心功能模块之一。AOP 与 IoC 容器的结合使用,为应用开发和 Spring 自身功能的扩展都提供了许多便利。下面先简单介绍一下 Spring AOP 的几个概念:

    1. Advice 通知:定义在连接点做什么,为切面增强提供织入接口,相当于 AOP 体系结构中的“切面”。
    2. Pointcut 切点:决定 Advice 通知应该作用于哪个连接点,也就是通过 Pointcut 来定义需要增强的方法的集合,集合的选取按照一定规则来完成。这个待增强的方法集合相当于 AOP 体系结构中的“基础”。
    3. Advisor 通知器:负责把 Advice 和 Pointcut 结合起来,相当于 AOP 体系结构中的“配置”。

    与 IoC 容器的衔接

    在 AopNamespaceHandler 里,注册了对 aspectj-autoproxy 标签的解析类 AspectJAutoProxyBeanDefinitionParser。

    public class AopNamespaceHandler extends NamespaceHandlerSupport {
        public void init() {
            // In 2.0 XSD as well as in 2.1 XSD.
            registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
            registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
            registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
    
            // Only in 2.0 XSD: moved to context namespace as of 2.1
            registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
        }
    }
    

    AspectJAutoProxyBeanDefinitionParser 类实现了 BeanDefinitionParser 接口,在其 parse 方法中注册了 AnnotationAwareAspectJAutoProxyCreator 类。

    class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
            extendBeanDefinition(element, parserContext);
            return null;
        }   
    }
    
    public abstract class AopConfigUtils {
        public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
            return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
        }
    }
    

    AnnotationAwareAspectJAutoProxyCreator 类实现了 BeanPostProcessor 接口,当 Spring 加载 Bean 时,会在实例化后调用其 postProcessAfterInitialization 方法

        // 位于父类 AbstractAutoProxyCreator 
        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;
        }
        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;
            }
    
            // 根据 class 获取对应的增强类 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;
        }
    

    getAdvicesAndAdvisorsForBean 方法获取用户定义的 Advice,createProxy 方法负责创建代理,createProxy 主要是由 ProxyFactory 类创建代理。

        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)) {
                // 如果使用接口代理,则设置代理接口
                Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
                for (Class<?> targetInterface : targetInterfaces) {
                    proxyFactory.addInterface(targetInterface);
                }
            }
    
            // 根据 advice 创建 advisor
            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 类,在设置了 advisor、targetInterface、targetSource 等之后,调用 getProxy 方法生成代理。

        public Object getProxy(ClassLoader classLoader) {
            return createAopProxy().getProxy(classLoader);
        }
        // 位于基类 ProxyCreatorSupport 中
        protected final synchronized AopProxy createAopProxy() {
            if (!this.active) {
                activate();
            }
            return getAopProxyFactory().createAopProxy(this);
        }
        //  AopProxyFactory 目前只有一个实现类 DefaultAopProxyFactory
        public AopProxyFactory getAopProxyFactory() {
            return this.aopProxyFactory;
        }
    

    在 getProxy 方法中,首先要调用 createAopProxy 创建代理类,createAopProxy 最终调用 DefaultAopProxyFactory 来创建代理:

        public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
            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.");
                }
                if (targetClass.isInterface()) {
                    return new JdkDynamicAopProxy(config);
                }
                if (!cglibAvailable) {
                    throw new AopConfigException(
                            "Cannot proxy target class because CGLIB2 is not available. " +
                            "Add CGLIB to the class path or specify proxy interfaces.");
                }
                return CglibProxyFactory.createCglibProxy(config);
            }
            else {
                return new JdkDynamicAopProxy(config);
            }
        }
    
        
        private static class CglibProxyFactory {
            public static AopProxy createCglibProxy(AdvisedSupport advisedSupport) {
                return new Cglib2AopProxy(advisedSupport);
            }
        }
    

    createAopProxy 中根据一些信息来决定使用 JDK 代理 JdkDynamicAopProxy,还是 Cglib 代理 Cglib2AopProxy?

    1. 如果目标类是接口,则使用 JDK 动态代理。
    2. 如果配置了 < aop:aspectj-autoproxy proxy-target-class="true"> 则优先使用 Cglib 代理。
    3. 如果采用激进优化策略,则使用 Cglib 代理。
    4. 如果目标类没有实现接口,则是以 Cglib 代理。

    AopProxy 实现

    在上面提到的 JdkDynamicAopProxy 和 Cglib2AopProxy 都是 AopProxy 接口的子类,这两个类分别负责调用 JDK 动态代理和 Cglib 代理来生成代理类。

    public interface AopProxy {
        // 创建代理
        Object getProxy();
        // 使用指定的 classLoader 创建代理
        Object getProxy(ClassLoader classLoader);
    }
    

    JdkDynamicAopProxy 代理类

    JdkDynamicAopProxy 实现了 AopProxy 接口,getProxy 方法中,主要是调用了 Proxy.newProxyInstance 方法来生成代理。

    final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
        public Object getProxy() {
            return getProxy(ClassUtils.getDefaultClassLoader());
        }
    
        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);
            findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
            return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
        }
    }
    

    Proxy.newProxyInstance 有三个参数:classLoader、代理接口集合、InvocationHandler。第三个参数的值为 this,因为 JdkDynamicAopProxy 同时也是实现了 InvocationHandler 接口,该接口有一个 invoke 方法,负责调用增强方法和目标方法。具体 Proxy.newProxyInstance 是如何生成代理的,可以看看这篇文章:深度剖析JDK动态代理机制

    public interface InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    }
    final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
        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 {
                // equals 方法处理
                if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                    return equals(args[0]);
                }
                // hashCode 方法处理
                if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                    return hashCode();
                }
                if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                        method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                    // Service invocations on ProxyConfig with the proxy config...
                    return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
                }
    
                Object retVal;
    
                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 = targetSource.getTarget();
                if (target != null) {
                    targetClass = target.getClass();
                }
    
                // 获取当前方法的拦截器链
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
                // 如果拦截器链为空则直接调用
                if (chain.isEmpty()) {
                    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
                }
                else {
                    // 将拦截器链和目标类等进行封装,并调用 proceed 执行
                    invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                    retVal = invocation.proceed();
                }
    
                if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
                        !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                    // 处理特殊情况
                    retVal = proxy;
                }
                return retVal;
            }
            finally {
                if (target != null && !targetSource.isStatic()) {
                    targetSource.releaseTarget(target);
                }
                if (setProxyContext) {
                    // Restore old proxy.
                    AopContext.setCurrentProxy(oldProxy);
                }
            }
        }
    }
    

    Cglib2AopProxy 代理类

    Cglib2AopProxy 也是类似的,实现了 AopProxy 方法,在 getProxy 中使用 Cglib 的 Enhancer 来生成了代理类。

    final class Cglib2AopProxy implements AopProxy, Serializable {
        public Object getProxy(ClassLoader classLoader) {
            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);
                    }
                }
    
                // 校验,final 类不可被代理
                validateClassIfNecessary(proxySuperClass);
    
                // 创建并设置 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.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
                enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
                enhancer.setInterceptDuringConstruction(false);
    
                Callback[] callbacks = getCallbacks(rootClass);
                // 设置拦截器
                enhancer.setCallbacks(callbacks);
                enhancer.setCallbackFilter(new ProxyCallbackFilter(
                        this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
    
                Class[] types = new Class[callbacks.length];
                for (int x = 0; x < types.length; x++) {
                    types[x] = callbacks[x].getClass();
                }
                enhancer.setCallbackTypes(types);
    
                // 创建代理类
                Object proxy;
                if (this.constructorArgs != null) {
                    proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);
                }
                else {
                    proxy = enhancer.create();
                }
    
                return proxy;
            }
            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);
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Spring 框架学习(四):AOP

          本文链接:https://www.haomeiwen.com/subject/sfbqpxtx.html