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();
    }
}
posted @ 2019-07-16 13:30  白芷呀  阅读(280)  评论(0编辑  收藏  举报