zoukankan      html  css  js  c++  java
  • spring(五):AOP

    AOP(Aspect Oriented Programming)

    面向切面编程,是一种编程范式,提供从另一个角度来考虑程序结构从而完善面向对象编程(OOP)。

    在进行OOP开发时,都是基于对组件(比如类)进行开发,然后对组件进行组合,OOP最大问题就是无法解耦组件进行开发。

    AOP为开发者提供一种进行横切关注点(比如日志关注点横切了支付关注点)分离并织入的机制,把横切关注点分离,然后通过某种技术织入到系统中,从而无耦合的完成了我们的功能。

    横切关注点可能包含很多,比如非业务的:日志、事务处理、缓存、性能统计、权限控制等;还可能是业务的:如某个业务组件横切于多个模块。

    基本概念

    • 连接点(Jointpoint):表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化、方法执行、方法调用、字段调用或处理异常等,Spring只支持方法执行连接点;“在哪里干”
    • 切入点(Pointcut):选择一组相关连接点的模式,即可以认为连接点的集合,Spring默认使用AspectJ语法;“在哪里干的集合”;[ <aop:aspectj-autoproxy/> 开启spring对@Aspectj的支持]
    • 通知(Advice):在连接点上执行的行为;“干什么”
    • 引入/内部类型声明(inter-type declaration):为已有的类添加额外新的字段或方法,Spring允许引入新的接口(必须对应一个实现)到所有被代理对象(目标对象);“干什么(引入什么)”
    • 切面(Aspect):横切关注点的模块化,比如日志组件。可以认为是通知、引入和切入点的组合,在Spring中可以使用Schema和@AspectJ方式进行组织实现;“在哪干和干什么集合”
    • 目标对象(Target Object):需要被织入横切关注点的对象,被代理对象;“对谁干”
    • 织入(Weaving):织入是一个过程,是将切面应用到目标对象从而创建出AOP代理对象的过程,织入可以在编译期、类装载期、运行期进行。
      • 编译时织入,生成完整功能的Java字节码,需特殊编译器(AspectJ)
      • 类加载时织入,AspectJ、AspectWerkz
      • 运行时织入,动态代理。@EnableAspectJAutoProxy。[Spring采用运行时]
    • AOP代理(AOP Proxy):AOP框架使用代理模式创建的对象,从而实现在连接点处插入通知,就是通过代理来对目标对象应用切面

    What-@Aspect

    Where-@Pointcut

    When-@Advice(@Before、@After、@AfterReturning、@AfterThrowing、@Around)

    在Spring中通过代理模式实现AOP,并通过拦截器模式以环绕连接点的拦截器链织入通知(即应用切面)

    通知类型

    • 前置通知(Before Advice):在切入点选择的连接点处的方法之前执行的通知,该通知不影响正常程序执行流程(除非该通知抛出异常,该异常将中断当前方法链的执行而返回)。
    • 后置通知(After Advice):在切入点选择的连接点处的方法之后执行的通知,包括如下类型的后置通知:
      • 后置返回通知(After returning Advice):在切入点选择的连接点处的方法正常执行完毕时执行的通知,必须是连接点处的方法没抛出任何异常正常返回时才调用后置通知。
      • 后置异常通知(After throwing Advice): 在切入点选择的连接点处的方法抛出异常返回时执行的通知,必须是连接点处的方法抛出任何异常返回时才调用异常通知。
      • 后置最终通知(After finally Advice): 在切入点选择的连接点处的方法返回时执行的通知,不管抛没抛出异常都执行,类似于Java中的finally块。
    • 环绕通知(Around Advices):环绕着在切入点选择的连接点处的方法所执行的通知,环绕通知可以在方法调用之前和之后自定义任何行为,并且可以决定是否执行连接点处的方法、替换返回值、抛出异常等等。

    通知顺序

    Spring中可以通过在切面实现类上实现org.springframework.core.Ordered接口或使用Order注解来指定切面优先级。在多个切面中,Ordered.getValue()方法返回值(或者注解值)较小值的那个切面拥有较高优先级。

    @Order(2)
    

    动态代理

    如果目标对象实现了接口,默认使用JDK,可以强制用CGLIB;否则,采用CGLIB。

    JDK动态代理

    只能为接口创建动态代理实例,而不能针对类。

    使用java.lang.reflect.Proxy动态代理实现,通过调用目标类的getClass().getInterfaces()方法获取目标对象的接口信息,并生成一个实现了代理接口的动态代理class,然后通过反射技术获得该class的构造函数,并利用构造函数生成实例,在调用具体方法前调用InvocationHandler处理。

    在Proxy这个类当中首先实例化一个对象ProxyClassFactory,然后在get方法中调用了apply方法,完成对代理类的创建:

    • generateProxyClass通过反射收集字段和属性然后生成字节
    • defineClass0 jvm内部完成对上述字节的load

    CGLIB动态代理

    主要是对指定的类生成一个子类,覆盖其中的方法。(不能通知final方法)

    利用asm开源包,采用字节码技术,为一个类创建子类,在子类中采用方法拦截(MethodInterceptor @override intercept()),拦截所有父类方法的调用,顺势织入横切逻辑。

    会产生两次构造器调用,第一次是目标类的构造器调用,第二次是CGLIB生成的代理类的构造器调用。

    设计分析

    1 为目标对象建立AopProxy代理对象

    在依赖注入时,实例化bean后都会调用getObjectForBeanInstance方法,这里就是处理FactoryBean的入口。

    通过配置和调用ProxyFactoryBean来完成代理对象的创建。

    配置通知器advisor、proxyFactoryBean(目标对象target、interceptorNames拦截器数组、目标对象接口数组)

    // ProxyFactoryBean
    	@Nullable
        public Object getObject() throws BeansException {
            // 对通知器链进行初始化
            // 通知器链封装了一系列的拦截器(需要从配置中读取)
            // 然后为代理对象的生成做准备
            this.initializeAdvisorChain();
            // 区分两种类型的Bean
            if (this.isSingleton()) {
                return this.getSingletonInstance();
            } else {
                ...
                return this.newPrototypeInstance();
            }
        }
    
        private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
            // 通知器链未初始化(初始化工作发生在应用第一次通过ProxyFactoryBean获取代理对象的时候)
            if (!this.advisorChainInitialized) {
                if (!ObjectUtils.isEmpty(this.interceptorNames)) {
                    ...
                    String[] var1 = this.interceptorNames;
                    int var2 = var1.length;
                    for(int var3 = 0; var3 < var2; ++var3) {
                        String name = var1[var3];
                        ...
                        if (name.endsWith("*")) {
                            ...
                        } else {
                            Object advice;
                            if (!this.singleton && !this.beanFactory.isSingleton(name)) {
                                // Prototype类型
                                advice = new ProxyFactoryBean.PrototypePlaceholderAdvisor(name);
                            } else {
                                // singleton类型:通过getBean获取通知器
                                advice = this.beanFactory.getBean(name);
                            }
    						// 将通知器加入拦截器链中
                            this.addAdvisorOnChainCreation(advice, name);
                        }
                    }
                }
    
                this.advisorChainInitialized = true;
            }
        }
    
        private synchronized Object getSingletonInstance() {
            if (this.singletonInstance == null) {
                this.targetSource = this.freshTargetSource();
                if (this.autodetectInterfaces && this.getProxiedInterfaces().length == 0 && !this.isProxyTargetClass()) {
                    // 判断需要代理的接口
                    Class<?> targetClass = this.getTargetClass();
                    ...
                    // 设置代理对象调用接口
                    this.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
                }
    
                super.setFrozen(this.freezeProxy);
                // createAopProxy:生成aop代理对象 ★调用父类的createAopProxy()
                // getProxy:<<AopProxy>>接口的两种实现--JdkDynamicAopProxy、CglibAopProxy
                this.singletonInstance = this.getProxy(this.createAopProxy());
            }
    
            return this.singletonInstance;
        }
    
        private synchronized Object newPrototypeInstance() {
            ...
            ProxyCreatorSupport copy = new ProxyCreatorSupport(this.getAopProxyFactory());
            TargetSource targetSource = this.freshTargetSource();
            copy.copyConfigurationFrom(this, targetSource, this.freshAdvisorChain());
            if (this.autodetectInterfaces && this.getProxiedInterfaces().length == 0 && !this.isProxyTargetClass()) {
                // 和上面一模一样的套路啊。。。
                Class<?> targetClass = targetSource.getTargetClass();
                if (targetClass != null) {
                    copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
                }
            }
            ...
            // 然后通过<<AopProxy>>接口的两种实现--JdkDynamicAopProxy、CglibAopProxy获取代理对象
            return this.getProxy(copy.createAopProxy());
        }
    
    // ProxyCreatorSupport
        protected final synchronized AopProxy createAopProxy() {
            if (!this.active) {
                this.activate();
            }
    
            // createAopProxy:<<AopProxyFactory>>接口的方法
            return this.getAopProxyFactory().createAopProxy(this);
        }
    
    // 具体实现:DefaultAopProxyFactory
        public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
            // 如果目标对象是接口类,使用jdk
            if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
                return new JdkDynamicAopProxy(config);
            } else {
                Class<?> targetClass = config.getTargetClass();
                if (targetClass == null) {
                    ...
                } else {
                    // ObjenesisCglibAopProxy extends CglibAopProxy 
                    return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
                }
            }
            // new的过程都是先从AdvisedSupport对象中取得配置的目标对象进行检查
        }
    
    // JdkDynamicAopProxy
        public Object getProxy(@Nullable ClassLoader classLoader) {
            ...
            // 首先从advised对象中获取代理对象的代理接口配置
            Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
            this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
            // 然后调用Proxy的newProxyInstance方法得到Proxy代理对象
            // 需要三个参数:类加载器、代理接口、回调方法所在对象
            // 回调方法用的是InvokeHandler的invoke回调入口
            return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
        }
    
    // CglibAopProxy
        public Object getProxy(@Nullable ClassLoader classLoader) {
            ...
            try {
                // 从advised对象中获取配置的target对象
                Class<?> rootClass = this.advised.getTargetClass();
                ...
                Class<?> proxySuperClass = rootClass;
                int x;
                if (ClassUtils.isCglibProxyClass(rootClass)) {
                    proxySuperClass = rootClass.getSuperclass();
                    Class<?>[] additionalInterfaces = rootClass.getInterfaces();
                    Class[] var5 = additionalInterfaces;
                    int var6 = additionalInterfaces.length;
    
                    for(x = 0; x < var6; ++x) {
                        Class<?> additionalInterface = var5[x];
                        this.advised.addInterface(additionalInterface);
                    }
                }
    			// 验证代理对象的接口设置
                this.validateClassIfNecessary(proxySuperClass, classLoader);
                // 创建并配置cglib的enhancer
                Enhancer enhancer = this.createEnhancer();
                if (classLoader != null) {
                    enhancer.setClassLoader(classLoader);
                    if (classLoader instanceof SmartClassLoader && ((SmartClassLoader)classLoader).isClassReloadable(proxySuperClass)) {
                        enhancer.setUseCache(false);
                    }
                }
                // 设置enhancer的代理接口、回调方法等
                enhancer.setSuperclass(proxySuperClass);
                enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
                enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
                enhancer.setStrategy(new CglibAopProxy.ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
                Callback[] callbacks = this.getCallbacks(rootClass);
                Class<?>[] types = new Class[callbacks.length];
    
                for(x = 0; x < types.length; ++x) {
                    types[x] = callbacks[x].getClass();
                }
    
                enhancer.setCallbackFilter(new CglibAopProxy.ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
                enhancer.setCallbackTypes(types);
                // 通过enhancer生成代理对象 ★
                // 注意这里有回调
                return this.createProxyClassAndInstance(enhancer, callbacks);
            }...
        }
    
    	// 这里是回调方法,通过设置DynamicAdvisedInterceptor拦截器完成AOP功能
        private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
            ...
            Callback aopInterceptor = new CglibAopProxy.DynamicAdvisedInterceptor(this.advised);
            ...
            return callbacks;
        }
    

    2 启动代理对象的拦截器来完成各种横切面的织入

    在第一步的过程中,拦截器已经配置到代理对象中,它是通过回调方法起作用。

    JdkDynamicAopProxy的invoke拦截
        @Nullable
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object oldProxy = null;
            boolean setProxyContext = false;
            TargetSource targetSource = this.advised.targetSource;
            Object target = null;
    
            Boolean var8;
            try {
                if (this.equalsDefined || !AopUtils.isEqualsMethod(method)) {
                    ...
    				// 得到目标对象
                    target = targetSource.getTarget();
                    Class<?> targetClass = target != null ? target.getClass() : null;
                    // 这个方法对象注册了拦截器
                    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                    // 没有设定拦截器链,直接调用target对象的方法
                    if (chain.isEmpty()) {
                        Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                        // 对target对象的方法调用是通过反射机制,然后使用invoke调用方法反射对象
                        retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                    } else {
                        // 拦截,通过ReflectiveMethodInvocation
                        MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                        // 沿着拦截器链继续前进
                        retVal = invocation.proceed();
                    }
                    ...
                }
                var8 = this.equals(args[0]);
            }...
            return var8;
        }
    
    
    CglibAopProxy的DynamicAdvisedInterceptor的intercept拦截
            @Nullable
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                ...
                try {
                    ...
                    // 得到目标对象
                    target = targetSource.getTarget();
                    Class<?> targetClass = target != null ? target.getClass() : null;
                    // 从advised取得配置好的AOP通知
                    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                    Object retVal;
                    // 若没有,则直接调用target对象的方法
                    if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                        Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                        retVal = methodProxy.invoke(target, argsToUse);
                    } else {
                        // 拦截,通过CglibMethodInvocation启动advice通知
                        // CglibMethodInvocation extends ReflectiveMethodInvocation
                        // 沿着拦截器链继续前进
                        retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
                    }
                    retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal);
                    var16 = retVal;
                }...
                return var16;
            }
    
    

    综上,都是从advised取得拦截器链的。

    拦截都是通过ReflectiveMethodInvocation的proceed方法实现的。

    如何将拦截器链配置进advised的?

    拦截器是ReflectiveMethodInvocation类中一个名为interceptorsAndDynamicMethodMatchers的List中的元素。

    this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    

    advised的getInterceptorsAndDynamicInterceptionAdvice是由advisorChainFactory实现的,它的具体类型是DefaultAdvisorChainFactory。

    DefaultAdvisorChainFactory通过AdvisorAdapterRegistry来适配ProxyFactoryBean中得到的通知器,注册拦截器。

    在ProxyFactoryBean的getObject方法中对advisor进行初始化时,从配置中获取了通知器。(通过实现BeanFactoryAware接口,设置回调方法委托给IoC容器)

    proceed方法
        @Nullable
        public Object proceed() throws Throwable {
            // 如果已经到拦截器链的末尾,直接调用目标对象的方法
            if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
                return this.invokeJoinpoint();
            } else {
                // 否则,得到下一个拦截器
                Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
                // 通过拦截器进行matches判断是否适用于横切增强的场合
                if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                    InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
                    Class<?> targetClass = this.targetClass != null ? this.targetClass : this.method.getDeclaringClass();
                    // 如果是,从拦截器得到通知器,并启动invoke方法
                    // 否则,迭代调用proceed方法
                    return dm.methodMatcher.matches(this.method, targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
                } else {
                    return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
                }
            }
        }
    
    advice通知是如何实现的?

    DefaultAdvisorChainFactory通过AdvisorAdapterRegistry来适配ProxyFactoryBean中得到的通知器,注册拦截器。

    // DefaultAdvisorChainFactory	
    	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
            // GlobalAdvisorAdapterRegistry是一个单例,作用是适配器
            AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
            Advisor[] advisors = config.getAdvisors();
            ...
    
            for(int var11 = 0; var11 < var10; ++var11) {
                Advisor advisor = var9[var11];
                if (advisor instanceof PointcutAdvisor) {
                    PointcutAdvisor pointcutAdvisor = (PointcutAdvisor)advisor;
                    if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    	...
                    	if (match) {
                            MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                            ...
                        }
                    }
                } 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;
        }
    

    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);封装着advice织入实现的入口。

    // DefaultAdvisorAdapterRegistry
    	public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
            List<MethodInterceptor> interceptors = new ArrayList(3);
            Advice advice = advisor.getAdvice();
            if (advice instanceof MethodInterceptor) {
                interceptors.add((MethodInterceptor)advice);
            }
    		// 对通知进行适配
            Iterator var4 = this.adapters.iterator();
            while(var4.hasNext()) {
                AdvisorAdapter adapter = (AdvisorAdapter)var4.next();
                // 如果适配器支持某种通知,则从对应的适配器中获取该类通知器的拦截器
                if (adapter.supportsAdvice(advice)) {
                    interceptors.add(adapter.getInterceptor(advisor));
                }
            }
            ...
        }
    

    我们知道,proceed处理拦截器的时候是通过dm.interceptor.invoke(this)拦截器的回调方法。下面举一个例子。

    class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
        MethodBeforeAdviceAdapter() {
        }
    
        public boolean supportsAdvice(Advice advice) {
            return advice instanceof MethodBeforeAdvice;
        }
    
        public MethodInterceptor getInterceptor(Advisor advisor) {
            MethodBeforeAdvice advice = (MethodBeforeAdvice)advisor.getAdvice();
            return new MethodBeforeAdviceInterceptor(advice);
        }
    }
    
    public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
        private final MethodBeforeAdvice advice;
    
        public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
            Assert.notNull(advice, "Advice must not be null");
            this.advice = advice;
        }
    
        // 先触发advice的before,然后才是proceed调用!
        // 因为这是method before!如果是其他的拦截器,顺序、具体实现又不一样了
        public Object invoke(MethodInvocation mi) throws Throwable {
            this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
            return mi.proceed();
        }
    }
    
  • 相关阅读:
    Ubuntu 13.10 x64 安装 Eclipse Android SDK Java开发IDE
    域名 TTL 查询
    mysql 常用设置:字符集编码、自动完成(自动提示)、监听外网ip
    PHP 设置:timezone、error_log
    数字发行:电子书、电影、游戏、音乐
    细节:php array会把string key自动转成int吗?
    REST URI设计:版本号放在http header中,rewrite配置
    Linux时区设置
    Linux添加sudo用户
    php curl常见错误:SSL错误、bool(false)
  • 原文地址:https://www.cnblogs.com/angelica-duhurica/p/11194315.html
Copyright © 2011-2022 走看看