Spring Aop - 使用ProxyFactoryBean实现Aop原理-第八篇

概述

使用ProxyFactoryBean来演示如何生成一个代理对象,并执行aop的过程,ProxyFactoryBean即前文交待的FactoryBean的子类,这里可以再回忆下FactoryBean与BeanFactory的区别,具体文章:https://blog.csdn.net/y510662669/article/details/105664281

ProxyFactoryBean见文知意,即用来生成代理的工厂bean。生成的bean是一个代理bean。

类结构

ProxyConfig: 用于维护所有的代理配置的基类。确保所有代理者都有一致的属性。如下:

public class ProxyConfig implements Serializable {

    /** use serialVersionUID from Spring 1.2 for interoperability */
    private static final long serialVersionUID = -8409359707199703185L;

    // 标记是否直接对目标类进行代理,而不是通过接口产生代理
    private boolean proxyTargetClass = false;

    // 标记是否对代理进行优化。启动优化通常意味着在代理对象被创建后,增强的修改将不会生效,因此默认值为false。
    // 如果exposeProxy设置为true,即使optimize为true也会被忽略。
    private boolean optimize = false;
    
    // 标记是否需要阻止通过该配置创建的代理对象转换为Advised类型,默认值为false,表示代理对象可以被转换为Advised类型
    boolean opaque = false;

    // 标记代理对象是否应该被aop框架通过AopContext以ThreadLocal的形式暴露出去。
    // 当一个代理对象需要调用它自己的另外一个代理方法时,这个属性将非常有用。默认是是false,以避免不必要的拦截。
    boolean exposeProxy = false;

    // 标记该配置是否需要被冻结,如果被冻结,将不可以修改增强的配置。
    // 当我们不希望调用方修改转换成Advised对象之后的代理对象时,这个配置将非常有用。
    private boolean frozen = false;
...
}

Advised: 一个Aop代理工厂的基础配置接口,可以用来配置:Interceptors、Advice、Advisors和代理的接口。

AdvisedSupport: 实现了Advised接口,同时继承ProxyConfig类,在Advised的接口作用上,加上了对代理的类的一些基础配置。

BeanFactoryAware : 实现了aware接口的类,可以在bean的初始化阶段执行回调,setBeanFactory会被调用,可以拿到BeanFactory对象。

BeanClassLoaderAware: 实现了aware接口的类,可以通过回调方法setBeanClassLoader获取到ClassLoader对象。

实例

<!--target目标-->
    <bean id="userService" class="com.yangt.risk.ao.proxy.UserServiceImpl"/>
    <!--通知器-->
    <bean id = "userAdvisor" class="com.yangt.risk.ao.proxy.UserServiceAdvisor"/>
    <!--ProxyFactoryBean-->
    <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="userService"/>
        <property name="interceptorNames">
            <list>
                <value>userAdvisor</value>
            </list>
        </property>
        <property name="proxyTargetClass" value="true"/>
    </bean>
public class ProxyRiskTest {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext pathXmlApplicationContext = new ClassPathXmlApplicationContext("spring-ioc-test1.xml");
        UserService userService = pathXmlApplicationContext.getBean("proxyFactoryBean", UserService.class);
        userService.getUserId();
    }

}
public class UserServiceAdvisor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("前置");
        Object result = invocation.proceed();
        System.out.println("后置");
        return result;
    }
}

输出结果:

使用ProxyFactoryBean生成代理Bean的过程

ProxyFactoryBean见文知意,即可以生成代理bean的bean,此类是FactoryBean的子类,真正获取代理bean的逻辑是在getObject方法内实现的。这里回顾下,BeanFactory与FactoryBean的区别,地址:https://blog.csdn.net/y510662669/article/details/105664281,从大的方面去看,生成代理bean主要有两大步骤:

1.生成AopProxy代理对象。

2.AopProxy代理对象执行拦截器。

1.生成AopProxy代理对象

  1. 首先会执行ApplicationContext的getBean逻辑,判断是FactoryBean的实现类,进而会执行ProxyFactoryBean内的getObject方法。

  2. getObject方法内,会执行initializeAdvisorChain(); 初始化执行Advisor责任链。Advisor会把Intercept和Advice捏合起来,最终放入到一个LinkedList责任链中。

  3. 如果ProxyFactoryBean是单例的,执行ProxyFactoryBean#getSingletonInstance逻辑,这里重点关注单例的逻辑。这里会调用createAopProxy生成一个代理类,如果是接口会用JdkDynamicAopProxy生成,否则使用ObjenesisCglibAopProxy生成。createAopProxy方法返回的是一个接口AopProxy,此接口有三个实现类,分别是:CglibAopProxy,JdkDynamicAopProxy,以及ObjenesisCglibAopProxy,ObjenesisCglibAopProxy继承了CglibAopProxy。

  4. 以下生成AopProxy的具体代码逻辑:

    @Override
    	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() || Proxy.isProxyClass(targetClass)) {
    				return new JdkDynamicAopProxy(config);
    			}
    			return new ObjenesisCglibAopProxy(config);
    		}
    		else {
    			return new JdkDynamicAopProxy(config);
    		}
    	}

    首先,如果ProxyConfig内的optimize(是否优化)设置为true或者isProxytagretClass设置为true,或者没有提供接口,则会进一步判断targetClass是不是接口,或者targetClass本身是否已经是代理类,如果是执行JdkDynamicAopProxy的逻辑,否则执行ObjenesisCglibAopProxy的逻辑,这里重点关注下JdkProxyDynamicAopProxy的逻辑,因为Cglib的逻辑有点复杂。

  5. JdkProxyDynamicAopProxy生成代理对象实例的具体逻辑:

    @Override
    	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, true);
    		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    	}

    这里会取this.advised的代理接口,说一下this.advised即org.springframework.aop.support.DefaultPointcutAdvisor,这个逻辑是在org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#wrap这里被判断的,因为我的例子里面的Advice对象实现了org.aopalliance.intercept.MethodInterceptor接口,所以会默认构造一个DefaultPointcutAdvisor对象出来。这里拿到的proxiedInterfaces代理类的接口是在前一步setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader)); 进行设置的,所以拿到的是我targetClass的接口,即UserService,classLoader也是UserService的classLoader,然后再调用JDK原始的代理类生成方法,proxy.newInstance即可生成代理对象的实例。因为JdkProxyDynamicAopProxy实现了InvocationHandler接口,所以默认的回调方法即invoke方法,即我们称为拦截器。

  6. CglibAopProxy生成代理对象实例的具体逻辑:

                Enhancer enhancer = createEnhancer();
    			if (classLoader != null) {
    				enhancer.setClassLoader(classLoader);
    				if (classLoader instanceof SmartClassLoader &&
    						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
    					enhancer.setUseCache(false);
    				}
    			}
    			enhancer.setSuperclass(proxySuperClass);
    			enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
    			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    			enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
    
    			Callback[] callbacks = getCallbacks(rootClass);
    			Class<?>[] types = new Class<?>[callbacks.length];
    			for (int x = 0; x < types.length; x++) {
    				types[x] = callbacks[x].getClass();
    			}
    			// fixedInterceptorMap only populated at this point, after getCallbacks call above
    			enhancer.setCallbackFilter(new ProxyCallbackFilter(
    					this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
    			enhancer.setCallbackTypes(types);
    
    			// Generate the proxy class and create a proxy instance.
    			return createProxyClassAndInstance(enhancer, callbacks);

    Cglib生成代理对象的逻辑通常是失业Enhancer对象,这里设置了Callback的回调,即拦截器,即:DynamicAdvisedInterceptor这个类。

2.AopProxy代理对象执行拦截器

AopProxy执行的逻辑较为复杂,这里以JdkDynamicAopProxy说一下整体流程:

1. 设置Advisor到职责链的前置工作:Advisor : 通知器,是Advice和PointCut的结合类,在ProxyFactoryBean中,会默认生成一个DefaultPointcutAdvisor,这个里面PointCut的引用的是TruePointCut,即过滤都会返回True,Advice通知对象需要通过构造方法构造。在ProxyFactoryBean会构造一个Advisor职责链,这个过程在前文有说明,在生成职责链的过程中,会调用DefaultAdvisorAdapterRegistry#wrap生成一个Advisor对象,即:DefaultPointcutAdvisor。在warp这个方法里规定了:只有实现了Advisor、MethodInterceptor、AdvisorAdapter这三个接口里面的任意一个接口,才能生成DefaultPointcutAdvisor这么一个对象。此外,在xml文件里面配置的interceptorNames,会作为name去bean工厂获取bean,作为一个Advice,传入DefaultAdvisorAdapterRegistry#wrap生成一个Advisor对象,加入到职责链中。

2. 因为JdkDynamicAopProxy实现了InvocationHandler接口,所以前面的方法生成AopProxy后,调用targetClass的原始方法后,invoke方法就会被回调执行。

3. 首先会经过一些列的判断是否需要进行拦截,如果没有拦截,则直接AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);利用反射直接调用targetClass类的方法,原理即:设置method.setAccessible(true);并且method.invoke(target, args);

4. 获取advised的List<MethodInterceptor>,即所有方法执行的切面。此处的advised对象即ProxyFactoryBean对象,MethodInterceptor是什么呢?这里可以理解为所有实现了org.aopalliance.intercept.MethodInterceptor接口的子类,我们前面的设置进入xml的interceptName的UserAdvisor就实现了此接口。

5. 判断上一步的list是否为空,如果为空,直接执行目标方法,即调用AopUtils.invokeJoinpointUsingReflection(this.advised, method, args)。

6. 如果不为空,生成一个org.springframework.aop.framework.ReflectiveMethodInvocation,调用proceed方法,proceed方法内首先会判断当前的index是不是列表里面的最后一个,如果是则直接调用targetClass的目标方法,如果不是,则获取列表内的第一个对象,这个时候对象是InterceptorAndDynamicMethodMatcher,这个对象是对MethodInterceptor的简单封装。会判断能否匹配上,这里面的匹配抽象的非常好,比如抽象了一个子类出来,AspectJ表达式匹配,这个就是我们最常用的,例如配置的Aop异常拦截等。如果能匹配上,则直接调用MethodInterceptor接口的invoke方法。其实这里就是已经触发Advice了。如果匹配不上则再次递归调用proceed方法。

具体代码proceed方法截图:

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

具体代码invoke方法截图:

// Get the interception chain for this method.
			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.
			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.
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed();
			}

总结

ProxyFactoryBean生成代理对象的过程还是比较复杂的,总体分为生成AopProxy代理对象,以及执行拦截的过程。在生成AopProxy的过程中,内部已经组织好了PointCut以及把自定义的Advice,通过DefaultPointcutAdvisor给组装好。前置工作准备好后,后续在切面执行过程中,就可以获取到多个Advice以及PointCut是否满足要求,进而直接调用,如果满足则触发通知Advice执行,否则直接执行原生的方法。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值