- 在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...");
}
}
- 测试源码:
@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();
}
- 测试结果:
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()
)。
会有上述特点的原因是:(1)Cglib采用FastClass方法回调方法。(2)Cglib代理对象是目标对象的子类,故super.run1()
执行的是目标对象的run1()
方法。
fci.f1.invoke(fci.i1, obj, args)
含义是,在代理类的FastClass对象中执行run1()
方法,而参数obj
对象去执行run1()
方法。而此处obj
对象是target
对象。
即递归出口中最终执行的是target
的run1()
,且结束调用。