《spring技术内幕》读书笔记3-AOP的实现
目录
2.1.2 ProxyFactoryBean的getObject()
1. Demo
首先是spring aop应用:
(1)准备工作:
初期只需要了解:advice接口的实现类描述了:aop代理要做什么事;pointcut接口的实现类描述了:aop代理在哪里做事;advisor则是对advice、pointcut的整合。
package com.abc;
//工人接口
public interface Worker {
void work();
}
//普通工人类
public class OrdinaryWorker implements Worker {
@Override
public void work() {
System.out.println("* * * * * 搬砖 * * * * *");
}
}
//资本家类
public class Capitalist {
public void work() {
System.out.println("$ ¥ $ ¥ $ ¥ $ ¥ $ ¥ $ ¥ $");
}
}
//工人增强器(手动滑稽)
public class WorkerAdvisor extends AbstractPointcutAdvisor {
@Override
public Advice getAdvice() {
return new WorkerAdvice();
}
@Override
public Pointcut getPointcut() {
String pattern = "com.abc.OrdinaryWorker.*";
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
pointcut.setPattern(pattern);
return pointcut;
}
static class WorkerAdvice implements AfterReturningAdvice, MethodBeforeAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("21:00 - 滴,下班:没有困难的工作,只有勇敢的打工人!");
}
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("9:00 - 滴,上班:早安打工人!");
}
}
}
//资本家增加器
public class CapitalistAdvisor extends AbstractPointcutAdvisor {
@Override
public Advice getAdvice() {
return new CapitalistAdvice();
}
@Override
public Pointcut getPointcut() {
String pattern = "com.abc.Capitalist.*";
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
pointcut.setPattern(pattern);
return pointcut;
}
static class CapitalistAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("(*^▽^*)又是愉快数钱的一天!");
}
}
}
(2)spring配置:
<bean id="workerAdvisor" class="com.abc.WorkerAdvisor"/>
<bean id="capitalistAdvisor" class="com.abc.CapitalistAdvisor"/>
<bean id="worker" class="com.abc.OrdinaryWorker"/>
<bean id="capitalist" class="com.abc.Capitalist"/>
<bean id="aopWorker" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref bean="worker"/>
</property>
<property name="interceptorNames">
<list>
<value>workerAdvisor</value>
<value>capitalistAdvisor</value>
</list>
</property>
</bean>
<bean id="aopCapitalist" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref bean="capitalist"></ref>
</property>
<property name="interceptorNames">
<list>
<value>workerAdvisor</value>
<value>capitalistAdvisor</value>
</list>
</property>
</bean>
(3)单测:
public class AopTest {
@Test
public void test() throws Exception {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("mytest/aoptest.xml"));
Object aopWorker = bf.getBean("aopWorker");
Object aopCapitalist = bf.getBean("aopCapitalist");
assert !(aopCapitalist instanceof Proxy);
assert aopWorker instanceof Proxy;
Capitalist capitalist = (Capitalist) aopCapitalist;
capitalist.work();
System.out.println("--------阶级分割线--------");
Worker worker = (Worker) aopWorker;
worker.work();
}
}
(4)执行结果:
$ ¥ $ ¥ $ ¥ $ ¥ $ ¥ $ ¥ $
(*^▽^*)又是愉快数钱的一天!
--------阶级分割线--------
9:00 - 滴,上班:早安打工人!
* * * * * 搬砖 * * * * *
21:00 - 滴,下班:没有困难的工作,只有勇敢的打工人!
思考:为什么断言能顺利执行 —— aopCapitalist不是Proxy的实例,而aopWorker是Proxy的实例???且看下面分解……
2. AOP的实现
2.1 生成代理
spring是如何生成目标对象的代理,即解读:Object aopWorker = bf.getBean("aopWorker");
2.1.1 ProxyFactoryBean的UML
"aopWorker"的类型是ProxyFactoryBean,UML图如下:
根据1:ProxyFactoryBean是工厂Bean,参考【读书笔记2-依赖注入】可知执行工厂bean的getObject方法
根据2:ProxyFactoryBean能感知自己所在的BeanFactory,参考《Spring技术内幕-第2版》2.5.7节
根据3:ProxyFactoryBean继承AdvisedSupport,有几个关键的成员变量:targetSource(被代理的目标对象)、interfaces(代理的接口)、advisors(增强器)
2.1.2 ProxyFactoryBean的getObject()
了解完PRoxyFactoryBean的getObject()逻辑后,单测的问题就有答案了。主要逻辑如下:
考虑到继承关系,通过property标签,既可以配置诸如:interceptorNames、targetName等来自ProxyFactoryBean的成员变量,也可以配置诸如targetSource、interfaces、advisors等来自AdvisedSupport的成员变量。
无论是基于jdk动态代理的JdkDynamicAopProxy,还是基于cglib的ObjenesisCglibAopProxy,都有1个成员变量:AdvisedSupport advised,记录了代理目标的配置信息。
2.2 执行拦截
spring生成目标对象的代理后,代理对象是如何执行被aop拦截的方法,即解读:((Worker) aopWorker).work()。
从2.1节可知,AopProxy有2种实现:JdkDynamicAopProxy、ObjenesisCglibAopProxy,下面就分析一下JdkDynamicAopProxy的情况
2.2.1 JdkDynamicAopProxy
Java动态代理对象执行被代理的接口方法时,会执行InvocationHandler接口的invoke()方法。
JdkDynamicAopProxy实现了InvocationHandler接口,invoke()方法的主要逻辑如下:
从整体大局了解代码逻辑后,很自然的明白为什么chain的泛型是Object,而不是Interceptor,因为元素还可能是InterceptorAndDynamicMethodMatcher类型。而isRuntime这种情况,应该是针对方法重载的情况,相同的方法签名信息,入参类型不同,需要运行时再判断是否匹配。
aop对于不同advice转成不同MethodInterceptor,采用了适配器模式。aop的几个关键元素关系大致如下:
本文地址:https://blog.csdn.net/ye201622021113/article/details/109590403
推荐阅读
-
9. Spark Streaming技术内幕 : Receiver在Driver的精妙实现全生命周期彻底研究和思考
-
Spring学习之路3-AOP及实现AOP的三种方式
-
《spring技术内幕》读书笔记3-AOP的实现
-
Spring技术内幕笔记(九)------ApplicationContext和Bean的初始化及销毁
-
《Spring技术内幕》的读者问题交流 SpringSVNEclipsemaven互联网
-
Spring技术内幕——深入解析Spring架构与设计原理(三)数据库的操作实现
-
Spring技术内幕——深入解析Spring架构与设计原理(四)Web MVC的实现
-
《Spring技术内幕》的读者问题交流 SpringSVNEclipsemaven互联网
-
Spring技术内幕——深入解析Spring架构与设计原理(一)IOC实现原理
-
Spring学习之路3-AOP及实现AOP的三种方式