SpringAOP[3]-Cglib代理流程分析
作者:互联网
原文:SpringAOP联盟(2)— Cglib代理流程分析 - 简书 (jianshu.com)
1. 在resources目录下加入logback-test.xml
的配置文件
<?xml version="1.0" encoding="UTF-8"?> <configuration> <springProperty scope="context" name="logPath" source="log.out.path" defalutValue="/app/test.log"/> <!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, --> <!-- appender是configuration的子节点,是负责写日志的组件。 --> <!-- ConsoleAppender:把日志输出到控制台 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d %p [%r] [%t] [%X{traceRootId}] (%file:%line\): %m%n</pattern> <!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 --> <charset>UTF-8</charset> </encoder> </appender> <!-- 控制台输出日志级别 --> <root level="TRACE"> <appender-ref ref="STDOUT"/> </root> <!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 --> <!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE --> </configuration>
@Slf4j public class Person { public void run1() { log.info("我在跑步1..."); } public void run2() { log.info("我在跑步2..."); } }
2. 测试源码:
@Test public void testProxyFactory() { Person person = new Person(); //被建议的类,即面向目标类生成代理类 ProxyFactory proxyFactory = new ProxyFactory(person); NameMatchMethodPointcut nameMatchMethodPointcut = new NameMatchMethodPointcut(); nameMatchMethodPointcut.addMethodName("run1"); //通知+切点=advisor DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(); advisor.setPointcut(nameMatchMethodPointcut); advisor.setAdvice(new MethodBeforeAdvice() { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("before Advice..."); } }); //加入第二个adsivor NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisor= new NameMatchMethodPointcutAdvisor(); nameMatchMethodPointcutAdvisor.addMethodName("run1"); nameMatchMethodPointcutAdvisor.setAdvice(new SimpleTraceInterceptor()); //第三个advisor NameMatchMethodPointcutAdvisor advisor3= new NameMatchMethodPointcutAdvisor(); advisor3.addMethodName("run2"); advisor3.setAdvice(new DebugInterceptor()); //advisor放入到adviced proxyFactory.addAdvisor(advisor); proxyFactory.addAdvisor(advisor3); proxyFactory.addAdvisor(nameMatchMethodPointcutAdvisor); //最后经过代理生成代理对象 Person proxy = (Person) proxyFactory.getProxy(); //执行方法 proxy.run1(); }
3. 测试结果
before Advice... 2019-12-27 14:09:02,397 TRACE [1089] [main] [] (AbstractTraceInterceptor.java:222): Entering method 'run1' of class [com.proxy.Person] 2019-12-27 14:09:02,428 INFO [1120] [main] [] (Person.java:19): 我在跑步1... 2019-12-27 14:09:02,429 TRACE [1121] [main] [] (AbstractTraceInterceptor.java:222): Exiting method 'run1' of class [com.proxy.Person]
流程解析
1. 将advisor交由advised管理
- advisor:增强器(由advice和pointcut组成)
- advised:代理对象配置类(代理对象的配置以及所有的advisor)
继承AdvisedSupport
的ProxyFactory
负责创建代理对象,创建出来的代理对象
不仅保存了target
对象,也保存了Advised
(所有Advisor
)对象、ProxyConfig
(代理对象的配置)对象。
AdvisedSupport
实现了Advised
接口大部分的方法。
Advisor
由Advice+Pointcut
组成,可以称为一个增强器,而ProxyFactory
管理着所有的Advisor
,根据Pointcut
(切点)配置决定为目标对象
的方法增加拦截。
调用ProxyFactory
的addAdvisor
实际上的是AdvisedSupport
实现的addAdvisorInternal
。
private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException { Assert.notNull(advisor, "Advisor must not be null"); if (isFrozen()) { throw new AopConfigException("Cannot add advisor: Configuration is frozen."); } if (pos > this.advisors.size()) { throw new IllegalArgumentException( "Illegal position " + pos + " in advisor list with size " + this.advisors.size()); } //将Advisor添加到LinkedList中 this.advisors.add(pos, advisor); //更新Advisors数组 updateAdvisorArray(); //清空methodCache(后文有描述) adviceChanged(); }
2. 创建出代理对象
源码位置:org.springframework.aop.framework.CglibAopProxy#getProxy
由上图所知,即使不存在advisor
,getProxy()
依旧生成了一个代理对象。
ProxyFactory的作用是将target与adviced中的所有advisors整合在一起,生成proxy对象。待执行具体方法进行拦截。
3. 拦截方法
当调用代理对象的
run1()
方法后,实际上执行的是DynamicAdvisedInterceptor
接口的intercept()
方法。
(1)首先获取到对应Method方法上的chain(拦截器链)。
(2)递归执行拦截方法+目标方法。
代理对象的运行:
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Object target = null; TargetSource targetSource = this.advised.getTargetSource(); try { //若是设置了exposeProxy=true属性,便可以在同一线程中获取代理对象 if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } //获取到目标对象 target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); //(重点关注)1. 获取advised的该方法上的过滤器链 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); } else { //(重点关注)2. 开始执行方法的回调 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }
3.1 获取过滤器链
依旧是AdvicedSupport
,代理对象配置类的方法,作用是获取方法上的拦截器链。
在addAdvisorInternal
方法中,最后执行的adviceChanged()
方法,实际上是调用methodCache.clear()
方法,即清空拦截器缓存List。
注意:MethodCacheKey
是由Method
对象+method.hashCode()
组成,确保key的唯一性。
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) { MethodCacheKey cacheKey = new MethodCacheKey(method); //每次加入advisor后均清空methodCache,于是需要重新的生成cached List<Object> cached = this.methodCache.get(cacheKey); if (cached == null) { cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; }
而实际上获取AdvisorChain
的方法是AdvisorChainFactory
接口实现的。
该方法作用有两个,
- 遍历所有的
Advisor
,若可以切入该方法(根据Pointcut配置决定),执行步骤2; - 将
Advisor
解析为MethodInterceptor[]
对象,并加入到List<Object> interceptorList
中。
@Override public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, @Nullable Class<?> targetClass) { //饿汉式单例,最终生成DefaultAdvisorAdapterRegistry对象。 AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); //获取所有的advisors Advisor[] advisors = config.getAdvisors(); List<Object> interceptorList = new ArrayList<>(advisors.length); Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); Boolean hasIntroductions = null; //处理advisors,将其转换为Interceptor for (Advisor advisor : advisors) { if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; //判断ClassFilter是否满足,PointcutAdvisor默认ClassFilter=true if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); boolean match; if (mm instanceof IntroductionAwareMethodMatcher) { if (hasIntroductions == null) { hasIntroductions = hasMatchingIntroductions(advisors, actualClass); } match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions); } else { match = mm.matches(method, actualClass); } //判断该方法上是否被advisor切入 if (match) { //将advisor中的内容转化为MethodInterceptor。 MethodInterceptor[] interceptors = registry.getInterceptors(advisor); if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } } 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; }
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
生成的注册器。该类的主要作用是将Advice
解析为MethodInterceptor
对象。
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable { private final List<AdvisorAdapter> adapters = new ArrayList<>(3); /** * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters. */ public DefaultAdvisorAdapterRegistry() { registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); } @Override public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<>(3); Advice advice = advisor.getAdvice(); //若是Advice实现了MethodInterceptor接口,直接加入到List中 if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } for (AdvisorAdapter adapter : this.adapters) { //若是advice实现了MethodBeforeAdvice等类型,则转换为MethodInterceptor,注意这些方法由子类实现。 if (adapter.supportsAdvice(advice)) { interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor[0]); } }
3.2 递归执行方法
interceptorsAndDynamicMethodMatchers
为上一步中解析得到该Method
中MethodInterceptor
的长度,即将要执行这些长度的拦截器方法。
@Override @Nullable public Object proceed() throws Throwable { //(递归出口)最开始的拦截器索引下标为-1。 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { //执行目标方法 return invokeJoinpoint(); } //interceptorsAndDynamicMethodMatchers为ArrayList,存储的是过滤器链 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; Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); if (dm.methodMatcher.matches(this.method, 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 { // 获取到MethodInterceptor链中的MethodInterceptor方法,开始回调。 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
拦截器回调方法:org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor#invoke
@Override public Object invoke(MethodInvocation mi) throws Throwable { //因为Advice被转换成为了MethodInterceptor对象,包装了invoke方法 this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); //继续执行(JoinPoint)后续的方法,即递归调用。 return mi.proceed(); }
递归出口——执行Joinpoint方法:
org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#invokeJoinpoint
@Override protected Object invokeJoinpoint() throws Throwable { if (this.methodProxy != null) { //回调方法 return this.methodProxy.invoke(this.target, this.arguments); } else { return super.invokeJoinpoint(); } }
实际上执行的是:org.springframework.cglib.proxy.MethodProxy#invoke
public Object invoke(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; //f1为Proxy的FastClass类,i1为run1()方法下标,obj为目标对象 //该代码的含义是:执行目标对象的run1()方法。 return fci.f1.invoke(fci.i1, obj, args); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } catch (IllegalArgumentException ex) { if (fastClassInfo.i1 < 0) throw new IllegalArgumentException("Protected method: " + sig1); throw ex; } }
Cglib详解...指出了生成一个Cglib的Proxy对象,实际上会生成3个文件,在Java代码中表示:
f1
表示的是代理类的FastClass对象;f2
表示目标类的FastClass对象i1
表示run1()
方法的下标(代理对象run1()
会经过拦截)。i2
表示CGLIB$run1$0
方法的下标(代理对象中该方法是super.run1()
)。
super.run1()
执行的是目标对象的run1()
方法。
fci.f1.invoke(fci.i1, obj, args)
含义是,在代理类的FastClass对象中执行run1()
方法,而参数obj
对象去执行run1()
方法。而此处obj
对象是target
对象。
即递归出口中最终执行的是target
的run1()
,且结束调用。
标签:run1,对象,流程,Cglib,advisor,SpringAOP,new,方法,method 来源: https://www.cnblogs.com/chenxingyang/p/15559342.html