概述
使用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代理对象
-
首先会执行ApplicationContext的getBean逻辑,判断是FactoryBean的实现类,进而会执行ProxyFactoryBean内的getObject方法。
-
getObject方法内,会执行initializeAdvisorChain(); 初始化执行Advisor责任链。Advisor会把Intercept和Advice捏合起来,最终放入到一个LinkedList责任链中。
-
如果ProxyFactoryBean是单例的,执行ProxyFactoryBean#getSingletonInstance逻辑,这里重点关注单例的逻辑。这里会调用createAopProxy生成一个代理类,如果是接口会用JdkDynamicAopProxy生成,否则使用ObjenesisCglibAopProxy生成。createAopProxy方法返回的是一个接口AopProxy,此接口有三个实现类,分别是:CglibAopProxy,JdkDynamicAopProxy,以及ObjenesisCglibAopProxy,ObjenesisCglibAopProxy继承了CglibAopProxy。
-
以下生成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的逻辑有点复杂。
-
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方法,即我们称为拦截器。
-
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执行,否则直接执行原生的方法。