Spring
AOP
Aop实现之AJC编译器
AJC
即aspectj-maven-plugin
插件,它可以实现静态编译代理,编译阶段 compile 对文件进行增强,可以从 生成的.class 文件可以看出
导入AJC依赖
1 2 3 4 5 6
| <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.13</version> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.11</version> <configuration> <complianceLevel>1.8</complianceLevel> <source>1.8</source> <target>1.8</target> <showWeaveInfo>true</showWeaveInfo> <Xlint>ignore</Xlint> <encoding>UTF-8</encoding> <skip>false</skip> </configuration> <executions> <execution> <configuration> <skip>false</skip> </configuration> <goals> <goal>compile</goal> </goals> </execution> </executions> </plugin>
|
1 2 3 4 5 6 7 8 9
| @Service public class MyService {
private static final Logger logger = LoggerFactory.getLogger(MyService.class);
public void execute() { logger.info("execute"); } }
|
1 2 3 4 5 6 7 8 9 10 11
| @Aspect @Component public class MyAspect {
private static final Logger logger = LoggerFactory.getLogger(MyAspect.class);
@Before("execution(* com.example.demo.service.MyService.execute())") public void before() { logger.info("before"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @SpringBootApplication public class SpringAopApplication {
private static final Logger logger = LoggerFactory.getLogger(SpringAopApplication.class);
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringAopApplication.class, args); MyService bean = context.getBean(MyService.class);
logger.info("service class:{}", bean.getClass());
bean.execute();
context.close(); } }
|
Aop实现之agent类加载
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Service public class MyService {
private static final Logger logger = LoggerFactory.getLogger(MyService.class);
public void execute() { logger.info("execute"); submit(); }
public void submit() { logger.info("submit"); } }
|
1 2 3 4 5 6 7 8 9 10 11
| @Aspect @Component public class MyAspect {
private static final Logger logger = LoggerFactory.getLogger(MyAspect.class);
@Before("execution(* com.example.demo.service.MyService.*())") public void before() { logger.info("before"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @SpringBootApplication public class SpringAopApplication {
private static final Logger logger = LoggerFactory.getLogger(SpringAopApplication.class);
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringAopApplication.class, args); MyService bean = context.getBean(MyService.class);
logger.info("service class:{}", bean.getClass());
bean.execute();
} }
|
我们发现间接调用的方法没有被增强,这是因为该方法的调用没有被容器代理,属于类中的this调用
使用agent类加载增强
1
| -javaagent:/Users/yuanjianwei/.m2/repository/org/aspectj/aspectjweaver/1.9.7/aspectjweaver-1.9.7.jar
|
使用 Arthas
类加载时增强后的反编译该字节码文件,发现agrent在类加载时对非贬义字节码文件进行了织入增强
1
| jad com.example.demo.service.MyService
|
Aop实现之proxy
JDK
JDK代理实现
JDK 只能代理 实现接口的类
代理目标
1 2 3 4
| public interface SmsService {
String send(String message); }
|
1 2 3 4 5 6 7 8 9 10 11
| public class SmsServiceImpl implements SmsService {
private static final Logger LOGGER = LoggerFactory.getLogger(SmsServiceImpl.class);
@Override public String send(String message) {
LOGGER.info("send message:" + message); return message; } }
|
代理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class DebugInvocationHandler implements InvocationHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(SmsServiceImpl.class);
private final Object target;
public DebugInvocationHandler(Object target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
LOGGER.info("before mothed:" + method.getName());
Object result = method.invoke(target, args);
LOGGER.info("after mothed:" + method.getName());
return result; } }
|
代理工厂
使用 Proxy.newProxyInstance
创建新的代理实例对象
1
| Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
|
1 2 3 4 5 6 7 8 9 10 11
| public class JdkProxyFactory {
public static Object getProxy(Object target) {
return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new DebugInvocationHandler(target) ); } }
|
1 2 3 4 5
| @Test public void test() { SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl()); smsService.send("Hello World!"); }
|
简单版本
JDK代理原理
模拟代理类实现
将 增强的内容 进行抽象
1 2 3 4
| public interface MyInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
|
将 增强的抽象方法 和 目标对象 作为成员变量注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class $Proxy implements SmsService {
private MyInvocationHandler myInvocationHandler;
private final Object target;
public $Proxy(MyInvocationHandler myInvocationHandler, Object target) { this.myInvocationHandler = myInvocationHandler; this.target = target; }
@Override public String send(String message) { try { return (String) myInvocationHandler.invoke( this, target.getClass().getMethod( new Object() {}.getClass().getEnclosingMethod().getName(), new Object() {}.getClass().getEnclosingMethod().getParameterTypes() ), new Object[]{message} ); } catch (RuntimeException | Error e) { throw e; } catch (Throwable e) { throw new UndeclaredThrowableException(e); } } }
|
通过 构造方法 获取对象,调用方法实现 功能增强
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Test public void test$Proxy() {
SmsServiceImpl smsService = new SmsServiceImpl();
$Proxy $Proxy = new $Proxy( (proxy, method, args) -> { log.info("before mothed:" + method.getName()); Object result = method.invoke(smsService, args); log.info("after mothed:" + method.getName()); return result; }, smsService );
$Proxy.send("Hello World!"); }
|
JDK代理源码
对于 字节码 进行 反编译
JDK代理字节码生成
JDK 代理类的生成直接是通过ASM生成字节码,没有通过对于Java源码(.class文件)的编译。通过对于字节码的反编译可以看到 Java源码。
ASM的作用是运行时动态生成字节码,没有对 源码的编译阶段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @Test public void testAsm() throws Exception { byte[] dump = $ProxyASMDump.dump();
ClassLoader classLoader = new ClassLoader() { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { return super.defineClass(name, dump, 0, dump.length); } }; Class<?> proxy = classLoader.loadClass("com.example.demo.$ProxyASM");
Constructor<?> constructor = proxy.getConstructor(InvocationHandler.class);
SmsService smsService = (SmsService) constructor.newInstance(new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { log.info("before mothed:" + method.getName()); Object result = method.invoke(new SmsServiceImpl(), args); log.info("after mothed:" + method.getName()); return result; } });
smsService.send("Hello Wolrd!"); }
|
Cglib
Cglib代理实现
1 2 3 4 5 6 7 8 9 10 11
| @Service public class SmsService {
private static final Logger logger = LoggerFactory.getLogger(SmsService.class);
public String send(String message) {
logger.info("send message:" + message); return message; } }
|
通过 Enhancer.create
创建代理类,两个参数:第一个是 Class type
即目标代理类,第二个是 Callback callback
,第二个参数我们自定义 Callback
的子类 MethodInterceptor
并重写 intercept
方法,intercept
用于拦截增强被代理类的方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Test public void test() {
SmsService smsService = (SmsService) Enhancer.create( SmsService.class, (MethodInterceptor) (o, method, objects, methodProxy) -> { log.info("before mothed:" + method.getName()); Object result = method.invoke(new SmsService(), objects); log.info("after mothed:" + method.getName()); return result; }); smsService.send("Hello world!"); }
|
Gglib 代理的本质是 方法的重写
,目标代理类是父类型,代理类是子类型,所以父类型的目标方法不能被 final 修饰
代理优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class DebugMethodInterceptor implements MethodInterceptor {
private final static Logger logger = LoggerFactory.getLogger(DebugMethodInterceptor.class);
@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
logger.info("before mothed:" + method.getName()); Object result = proxy.invokeSuper(obj, args); logger.info("after mothed:" + method.getName()); return result; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class CglibProxyFactory {
public static Object getProxy(Class<?> clazz) { Enhancer enhancer = new Enhancer(); enhancer.setClassLoader(clazz.getClassLoader()); enhancer.setSuperclass(clazz); enhancer.setCallback(new DebugMethodInterceptor()); return enhancer.create(); } }
|
1 2 3 4 5 6 7
| @Test public void testProxy() {
SmsService proxy = (SmsService) CglibProxyFactory.getProxy(SmsService.class);
proxy.send("Hello World!"); }
|
Cglib代理原理
Cglib 代理类 的本质是继承 代理目标类,并 重写代理方法 对 代理方法进行增强。
通过 实现 MethodInterceptor
接口方法,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class ProxyService extends SmsService {
private MethodInterceptor methodInterceptor;
private static final Method method;
static { try { method = SmsService.class.getDeclaredMethod("send", String.class); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } }
public ProxyService(MethodInterceptor methodInterceptor) { this.methodInterceptor = methodInterceptor; }
@Override public String send(String message) { try { return (String) methodInterceptor.intercept( this, method, new Object[]{message}, null ); } catch (Throwable e) { throw new RuntimeException(e); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Test public void test$Proxy() { SmsService smsService = new SmsService();
ProxyService proxyService = new ProxyService( (obj, method, args, proxy) -> { log.info("before mothed:" + method.getName()); Object result = method.invoke(smsService, args); log.info("after mothed:" + method.getName()); return result; } );
proxyService.send("Hello World!"); }
|
Cglib MethodProxy
MethodInterceptor
接口中的回调的方法有一个 MethodProxy
,可以避免通过反射调用被代理的方法而是直接调用
新增一个方法调用父类的原始方法 super.send()作为本来的原始功能方法,使用 MethodProxy.create() 进行创建 MethodProxy 方法代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| public class ProxyService extends SmsService {
private MethodInterceptor methodInterceptor;
private static final Method method;
private static final MethodProxy methodProxy;
static { try { method = SmsService.class.getDeclaredMethod("send", String.class); methodProxy = MethodProxy.create( SmsService.class, ProxyService.class, "(Ljava/lang/String;)Ljava/lang/String;", "send", "superSend" ); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } }
public ProxyService(MethodInterceptor methodInterceptor) { this.methodInterceptor = methodInterceptor; }
public String superSend(String message) { return super.send(message); }
@Override public String send(String message) { try { return (String) methodInterceptor.intercept( this, method, new Object[]{message}, methodProxy ); } catch (Throwable e) { throw new RuntimeException(e); } } }
|
在调用目标方法时,不是通过 反射调用,而是通过 方法代理对象 调用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Test public void test$Proxy() {
SmsService smsService = new SmsService();
ProxyService proxyService = new ProxyService( (obj, method, args, proxy) -> {
log.info("before mothed:" + method.getName());
Object result = proxy.invokeSuper(obj, args); log.info("after mothed:" + method.getName()); return result; } );
proxyService.send("Hello World!"); }
|
MethodProxy原理
MethodProxy
在调用 invoke
和 invokeSuper
会避免反射调用,它通过 FastClass
来避免反射,Cglib 在调用这两个方法时,会分别生成两个代理类(两个FastClass的子类),通过调用代理类中的方法避免反射
methodProxy.invoke(代理目标对象,args)
当我们调用 Method.create()
静态方法时,底层会创建一个FastClass的子类(目的是避免方法的反射调用)
- 当创建MethodProxy对象时,会构建
Signature
方法签名信息(包括方法名称和参数返回值)
- 代理类会根据传人的
Signature
定义目标方法的编号
- 代理类中根据获取方法的定义的编号调用指定的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public abstract class AbstractFastClass {
public abstract int getIndex(Signature signature);
public abstract Object invoke(int index, Object target, Object[] args); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class TargetFastClass extends AbstractFastClass {
static Signature s0 = new Signature("save", "(Ljava/lang/String;)Ljava/lang/String;");
@Override public int getIndex(Signature signature) { if (s0.equals(signature)) { return 0; } return -1; }
@Override public Object invoke(int index, Object target, Object[] args) { if (index == 0) { return (String) ((SmsService) target).send((String) args[0]); } return null; } }
|
1 2 3 4 5 6 7 8
| @Test public void testTargetFastClass() { TargetFastClass targetFastClass = new TargetFastClass(); int index = targetFastClass.getIndex( new Signature("send", "(Ljava/lang/String;)Ljava/lang/String;") ); targetFastClass.invoke(index, new SmsService(), new Object[]{"Hello World!"}); }
|
methodProxy.invokeSuper(代理对象,args)
调用 methodProxy.invokeSuper 的原理和调用 methodProxy.invoke 基本一致,唯一不同的是 获取的是 代理类中 的带原始方法的方法签名和定义编号,而 methodProxy.invoke 获取的是 代理目标类中的原始方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class ProxyFastClass extends AbstractFastClass {
static Signature s0 = new Signature("superSend", "(Ljava/lang/String;)Ljava/lang/String;");
@Override public int getIndex(Signature signature) { if (s0.equals(signature)) { return 0; } return -1; }
@Override public Object invoke(int index, Object target, Object[] args) { if (index == 0) { return (String) ((ProxyService) target).superSend((String) args[0]); } return null; } }
|
1 2 3 4 5 6 7 8 9
| @Test public void testProxyFastClass() { ProxyFastClass proxyFastClass = new ProxyFastClass(); int index = proxyFastClass.getIndex( new Signature("superSend", "(Ljava/lang/String;)Ljava/lang/String;") ); proxyFastClass.invoke(index, new ProxyService(new DebugMethodInterceptor()), new Object[]{"Hello World!"}); }
|
Spring代理选择
Spring代理选择规则
切点:增强匹配的规则
通知:具体增强的逻辑
切面:切点和通知的组合
两个切面:aspect
和 asvisor
aspect
是 通知和切点的组合集合
advisor
是 更细粒度的切面,只包含一个切点和通知
aspect
在生效之前会拆解成多个 advisor
切面实现
切点 在 org.springframework.aop
包下的 PointCut
接口实现
可以使用 AspectJExpressionPointcut
根据 JExpression 表达式来进行模式匹配
1 2 3 4
| AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* submit())");
|
使用 MethodInterceptor 设置通知即功能增强
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @Test public void testAop() { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression("execution(* submit())"); MethodInterceptor methodInterceptor = new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { logger.info("before submit"); Object result = invocation.proceed(); logger.info("after submit"); return result; } }; DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, methodInterceptor);
ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(new TargetService1()); proxyFactory.addAdvisor(advisor);
TargetService1 targetService1 = (TargetService1) proxyFactory.getProxy(); targetService1.execute(); targetService1.submit(); }
|
通过 调试 发现,上述 实例 Spring 使用 Cglib 生成的代理对象
代理选择
当 ProxyFactory
间接继承ProxyConfig
,ProxyConfig
内部存在一个成员变量 proxyTargetClass
(默认为 false
) 决定了 Spring 的代理方式
- 当
proxyTargetClass = false
时,代理目标实现接口,使用**JdkDynamicAopProxy
**即 JDK
实现代理;代理没有实现接口,使用 **ObjenesisCglibAopProxy
**即 Cglib
实现代理
- 当
proxyTargetClass = false
时,总使用**ObjenesisCglibAopProxy
**即 Cglib
实现代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| @Test public void testAop() { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression("execution(* submit())"); MethodInterceptor methodInterceptor = new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { logger.info("before submit"); Object result = invocation.proceed(); logger.info("after submit"); return result; } }; DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, methodInterceptor);
TargetService1 targetService = new TargetService1();
ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(targetService); proxyFactory.setInterfaces(targetService.getClass().getInterfaces());
proxyFactory.addAdvisor(advisor);
Target targetService1 = (Target) proxyFactory.getProxy(); targetService1.execute(); targetService1.submit(); }
|
切点匹配
常见切点匹配实现
Spring
用 切点PointCut
判断将来的目标方法 是否要进行功能增强。AspectJExpressionPointcut
是 PointCut
的一种具体实现,它根据切点表达式进行方法的模式匹配。
创建 AspectJExpressionPointcut
对象,调用 setExpression
设置切点表达式,可以通过 matches
方法判断是否与切点表达式匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Transactional(rollbackFor = Exception.class) public class TransactionalService {
private static final Logger logger = LoggerFactory.getLogger(TransactionalService.class);
@Transactional(rollbackFor = Exception.class) public void execute() { logger.info("execute"); }
public void submit() { logger.info("submit"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Test public void testTarget() throws NoSuchMethodException {
AspectJExpressionPointcut aspectJExpressionPointcut1 = new AspectJExpressionPointcut(); aspectJExpressionPointcut1.setExpression("execution(* submit())"); logger.info("execute:{}", aspectJExpressionPointcut1.matches(TargetService.class.getMethod("execute"), TargetService.class)); logger.info("submit:{}", aspectJExpressionPointcut1.matches(TargetService.class.getMethod("submit"), TargetService.class));
AspectJExpressionPointcut aspectJExpressionPointcut2 = new AspectJExpressionPointcut(); aspectJExpressionPointcut2.setExpression("@annotation(org.springframework.transaction.annotation.Transactional)"); logger.info("execute:{}", aspectJExpressionPointcut2.matches(TargetService.class.getMethod("execute"), TargetService.class)); logger.info("submit:{}", aspectJExpressionPointcut2.matches(TargetService.class.getMethod("submit"), TargetService.class)); }
|
@Transaction实现
AspectJExpressionPointcut
只能对于方法进行模式匹配,不能匹配类上的和接口上
StaticMethodMatcherPointcut
是一个实现 PointCut 的抽象类,可以规定 具体的匹配规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @Test public void testTransactionalAnnotation() throws NoSuchMethodException {
StaticMethodMatcherPointcut staticMethodMatcherPointcut = new StaticMethodMatcherPointcut() { @Override public boolean matches(Method method, Class<?> targetClass) {
MergedAnnotations mergedAnnotations = MergedAnnotations.from(method, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY); if (mergedAnnotations.isPresent(Transactional.class)) { return true; }
mergedAnnotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY); if (mergedAnnotations.isPresent(Transactional.class)) { return true; } return false; } }; logger.info("execute:{}", staticMethodMatcherPointcut.matches(TransactionalService.class.getMethod("execute"), TransactionalService.class)); logger.info("submit:{}", staticMethodMatcherPointcut.matches(TransactionalService.class.getMethod("submit"), TransactionalService.class)); }
|
从@Aspect到Advisor
Spring
切面分为 @Aspect
切面 和 Advisor
切面
@Aspect
可以有多个切点和切面,Advisor
只能有一个切点和切面
Spring 处理 高级的 @Aspect
切面,会将 高级的 @Aspect
切面 转换 低级 Advisor
切面
高级 @Aspect 切面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Aspect public class TestAspect {
private static final Logger logger = LoggerFactory.getLogger(TestAspect.class);
@Before("execution(* submit())") public void before() { logger.info("aspect before"); }
@After("execution(* submit())") public void after() { logger.info("aspect after"); } }
|
低级 Advisor 切面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Configuration public class AdvisorConfig {
private static final Logger logger = LoggerFactory.getLogger(AdvisorConfig.class);
@Bean public Advisor testAdvisor(MethodInterceptor testMethodInterceptor) {
AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut(); aspectJExpressionPointcut.setExpression("execution(* submit())");
return new DefaultPointcutAdvisor(aspectJExpressionPointcut, testMethodInterceptor); }
@Bean public MethodInterceptor testMethodInterceptor() { return invocation -> { logger.info("advisor before"); Object result = invocation.proceed(); logger.info("advisor after"); return result; }; } }
|
AnnotationAwareAspectJAutoProxyCreator
后置处理器
AnnotationAwareAspectJAutoProxyCreator 后置处理器的核心方法
- 查找所有符合条件的 切面 并 将高级的
Aspect
切面转换为 Advisor
切面
- 为 有必要的 Bean 即有资格(模式匹配上的)来创建代理对象,内部调用了
findEligibleAdvisors
,当 Advisor
集合不为空则 创建代理对象
由于 AnnotationAwareAspectJAutoProxyCreator
后处理器,方法由 protect 修饰,所以 只能同一个包下/子类/反射 可以调用。这里 测试类包名修改成与 AnnotationAwareAspectJAutoProxyCreator
位置一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| package org.springframework.aop.framework.autoproxy;
import com.example.demo.advisor.AdvisorConfig; import com.example.demo.aspect.TestAspect; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.springframework.aop.Advisor; import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.ConfigurationClassPostProcessor; import org.springframework.context.support.GenericApplicationContext;
import java.util.List;
@Slf4j @SpringBootTest public class SpringDemoAopTest {
static class Target { public void execute() { log.info("execute"); }
public void submit() { log.info("submit"); } }
@Test public void testPointCut() { GenericApplicationContext genericApplicationContext = new GenericApplicationContext(); genericApplicationContext.registerBean("testAspect", TestAspect.class); genericApplicationContext.registerBean("advisorConfig", AdvisorConfig.class);
genericApplicationContext.registerBean(ConfigurationClassPostProcessor.class); genericApplicationContext.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
genericApplicationContext.refresh();
AnnotationAwareAspectJAutoProxyCreator creator = genericApplicationContext.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
List<Advisor> advisor1 = creator.findEligibleAdvisors(Target.class, "target"); advisor1.forEach(advisor -> log.info("advisor:{}", advisor));
Object o = creator.wrapIfNecessary(new Target(), "target", "target"); log.info("class:{}", o.getClass()); Target target = (Target) o; target.submit(); } }
|
高级转换低级时机和代理生成时机
代理对象的创建时机一般是在 初始化之后 ,另外 当发生循环依赖时, 会发生在 创建实例 和 依赖注入之间,因为在 依赖注入的对象 并非 原始对象,而是代理对象
1
| 创建实例 -> (*) 依赖注入 -> 初始化(*)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
| @Slf4j @SpringBootTest public class SpringDemoProxyTest {
@Configuration static class Config {
@Bean public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() { return new AnnotationAwareAspectJAutoProxyCreator(); }
@Bean public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor() { return new AutowiredAnnotationBeanPostProcessor(); }
@Bean public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() { return new CommonAnnotationBeanPostProcessor(); }
@Bean public Advisor advisor(MethodInterceptor methodInterceptor) { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression("execution(* submit())");
return new DefaultPointcutAdvisor(pointcut, methodInterceptor); }
@Bean public MethodInterceptor methodInterceptor() { return invocation -> { log.info("before"); Object result = invocation.proceed(); log.info("after"); return result; }; }
@Bean public Bean1 bean1() { return new Bean1(); }
@Bean public Bean2 bean2() { return new Bean2(); } }
static class Bean1 {
public Bean1() { log.info("构造方法"); }
public void submit() { log.info("submit"); }
@PostConstruct public void init() { log.info("init"); }
@Autowired public void setBean2(Bean2 bean2) { log.info("依赖注入:{}", bean2.getClass()); } }
static class Bean2 {
public Bean2() { log.info("构造方法"); }
@Autowired public void setBean1(Bean1 bean1) { log.info("依赖注入:{}", bean1.getClass()); }
public void submit() { log.info("submit"); }
@PostConstruct public void init() { log.info("init"); } }
@Test public void test() { GenericApplicationContext genericApplicationContext = new GenericApplicationContext(); genericApplicationContext.registerBean(ConfigurationClassPostProcessor.class); genericApplicationContext.registerBean(Config.class); genericApplicationContext.refresh(); genericApplicationContext.close(); } }
|
我们分析一下 依赖注入的情况:当注入Bean1时,首先调用 Bean1 的构造,然后进行依赖注入 Bean2 ,此时 Bean2 并没有,此时去 Bean2 的生成流程,先构造,再进行依赖注入,在依赖注入时,需要一个 被代理的 Bean1,此时发生 Bean1 的代理在 Bean1 依赖注入之前被创建,创建代理的对象被创建并存放到二级缓存中
但是 依赖注入与初始化 不应该被增强,仍然使用的是原始对象
Order 切面优先级
切面执行的优先级 可以被控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Configuration public class AdvisorConfig {
private static final Logger logger = LoggerFactory.getLogger(AdvisorConfig.class);
@Bean public Advisor testAdvisor(MethodInterceptor testMethodInterceptor) {
AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut(); aspectJExpressionPointcut.setExpression("execution(* submit())");
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(aspectJExpressionPointcut, testMethodInterceptor); advisor.setOrder(2); return advisor; }
@Bean public MethodInterceptor testMethodInterceptor() { return invocation -> { logger.info("advisor before"); Object result = invocation.proceed(); logger.info("advisor after"); return result; }; } }
|
高级切面转换为低级切面
调用 AnnotationAwareAspectJAutoProxyCreator.wrapIfNecessary()
判断是否有资格被代理并返回代理对象,该方法内部会调用 findEligibleAdvisors()
方法进行匹配 符合条件的PointCut
添加到 Advisor
集合中,并将 高级切面 转换为 低级切面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| @Test public void testFindEligibleAdvisors() {
AspectInstanceFactory aspectInstanceFactory = new SingletonAspectInstanceFactory(new TestAspect());
List<Advisor> advisors = new ArrayList<>();
for (Method declaredMethod : TestAspect.class.getDeclaredMethods()) { if (declaredMethod.isAnnotationPresent(Before.class)) { Before annotation = declaredMethod.getAnnotation(Before.class);
AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut(); aspectJExpressionPointcut.setExpression(annotation.value());
AspectJMethodBeforeAdvice aspectJMethodBeforeAdvice = new AspectJMethodBeforeAdvice( declaredMethod, aspectJExpressionPointcut, aspectInstanceFactory );
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor(aspectJExpressionPointcut, aspectJMethodBeforeAdvice);
advisors.add(defaultPointcutAdvisor); } } advisors.forEach(advisor -> log.info("advisor:{}", advisor)); }
|
输出 一个 Advisor 切面
底层通知实现类
- 前置通知底层通知实现类:
AspectJMethodBeforeAdvice
- 环绕通知底层通知实现类:
AspectJAroundAdvice
- 返回通知底层通知实现类:
AspectJAfterReturningAdvice
- 异常通知底层通知实现类:
AspectJAfterThrowingAdvice
- 后置通知底层通知实现类:
AspectJAfterAdvice
静态通知调用
适配器模式
不同通知都会统一转换为环绕通知 MethodInterceptor
无论 ProxyFactory 基于什么方式创建代理对象,都会被统一转换为一个 MethodInterceptor
对象执行,这体现了适配器模式。做到 对于外部区分 Before
,Around
,AfterReturning
,(After
,AfterThrowing
本身已经实现了 MethodInterceptor
无需转换) ,内部统一使用 环绕通知,同意转换为 MethodInterceptor
对象执行
由于 Advisor 可能存在多个,一个接着一个的调用,因此需要一个调用链对象 MethodInterceptor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| @Test public void testFindEligibleAdvisors() throws NoSuchMethodException {
AspectInstanceFactory aspectInstanceFactory = new SingletonAspectInstanceFactory(new TestAspect());
List<Advisor> advisors = new ArrayList<>();
for (Method declaredMethod : TestAspect.class.getDeclaredMethods()) { if (declaredMethod.isAnnotationPresent(Before.class)) { Before annotation = declaredMethod.getAnnotation(Before.class);
AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut(); aspectJExpressionPointcut.setExpression(annotation.value());
AspectJMethodBeforeAdvice aspectJMethodBeforeAdvice = new AspectJMethodBeforeAdvice( declaredMethod, aspectJExpressionPointcut, aspectInstanceFactory );
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor(aspectJExpressionPointcut, aspectJMethodBeforeAdvice);
advisors.add(defaultPointcutAdvisor); } else if (declaredMethod.isAnnotationPresent(AfterReturning.class)) { AfterReturning annotation = declaredMethod.getAnnotation(AfterReturning.class);
AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut(); aspectJExpressionPointcut.setExpression(annotation.value());
AspectJAfterReturningAdvice aspectJAfterReturningAdvice = new AspectJAfterReturningAdvice( declaredMethod, aspectJExpressionPointcut, aspectInstanceFactory );
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor(aspectJExpressionPointcut, aspectJAfterReturningAdvice);
advisors.add(defaultPointcutAdvisor); } else if (declaredMethod.isAnnotationPresent(Around.class)) { Around annotation = declaredMethod.getAnnotation(Around.class);
AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut(); aspectJExpressionPointcut.setExpression(annotation.value());
AspectJAroundAdvice aspectJAroundAdvice = new AspectJAroundAdvice( declaredMethod, aspectJExpressionPointcut, aspectInstanceFactory );
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor(aspectJExpressionPointcut, aspectJAroundAdvice);
advisors.add(defaultPointcutAdvisor); } }
advisors.forEach(advisor -> log.info("advisor:{}", advisor));
ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(new Target()); proxyFactory.addAdvisors(advisors);
List<Object> interceptorsAndDynamicInterceptionAdvices = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("submit"), Target.class); interceptorsAndDynamicInterceptionAdvices.forEach(interceptorsAndDynamicInterceptionAdvice -> log.info("interceptorsAndDynamicInterceptionAdvice:{}", interceptorsAndDynamicInterceptionAdvice)); }
|
适配器
MethodBeforeAdviceAdapter
将 AspectJMethodBeforeAdvice
转换为 MethodInterceptor
在创建代理对象时,通过适配器将 通知 统一转换为 环绕通知MethodInterceptor
责任链模式
代理对象 内部通过 调用链接口 MethodInvocation
调用 目标对象 和 环绕通知集合
1 2 3
| protected ReflectiveMethodInvocation( Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments, @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| @Slf4j @SpringBootTest public class SpringDemoAdvisorTest {
static class Target {
public void execute() { log.info("execute"); }
public void submit() { log.info("submit"); } }
@Test public void testFindEligibleAdvisors() throws Throwable {
AspectInstanceFactory aspectInstanceFactory = new SingletonAspectInstanceFactory(new TestAspect());
List<Advisor> advisors = new ArrayList<>();
for (Method declaredMethod : TestAspect.class.getDeclaredMethods()) { if (declaredMethod.isAnnotationPresent(Before.class)) { Before annotation = declaredMethod.getAnnotation(Before.class);
AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut(); aspectJExpressionPointcut.setExpression(annotation.value());
AspectJMethodBeforeAdvice aspectJMethodBeforeAdvice = new AspectJMethodBeforeAdvice( declaredMethod, aspectJExpressionPointcut, aspectInstanceFactory );
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor(aspectJExpressionPointcut, aspectJMethodBeforeAdvice);
advisors.add(defaultPointcutAdvisor); } else if (declaredMethod.isAnnotationPresent(AfterReturning.class)) { AfterReturning annotation = declaredMethod.getAnnotation(AfterReturning.class);
AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut(); aspectJExpressionPointcut.setExpression(annotation.value());
AspectJAfterReturningAdvice aspectJAfterReturningAdvice = new AspectJAfterReturningAdvice( declaredMethod, aspectJExpressionPointcut, aspectInstanceFactory );
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor(aspectJExpressionPointcut, aspectJAfterReturningAdvice);
advisors.add(defaultPointcutAdvisor); } else if (declaredMethod.isAnnotationPresent(Around.class)) { Around annotation = declaredMethod.getAnnotation(Around.class);
AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut(); aspectJExpressionPointcut.setExpression(annotation.value());
AspectJAroundAdvice aspectJAroundAdvice = new AspectJAroundAdvice( declaredMethod, aspectJExpressionPointcut, aspectInstanceFactory );
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor(aspectJExpressionPointcut, aspectJAroundAdvice);
advisors.add(defaultPointcutAdvisor); } }
advisors.forEach(advisor -> log.info("advisor:{}", advisor));
Target target = new Target(); ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(target); proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE); proxyFactory.addAdvisors(advisors);
List<Object> interceptorsAndDynamicInterceptionAdvices = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice( Target.class.getMethod("submit"), Target.class ); interceptorsAndDynamicInterceptionAdvices.forEach(interceptorsAndDynamicInterceptionAdvice -> log.info("interceptorsAndDynamicInterceptionAdvice:{}", interceptorsAndDynamicInterceptionAdvice));
MethodInvocation methodInvocation = new ReflectiveMethodInvocation( null, target, Target.class.getMethod("submit"), new Object[0], Target.class, interceptorsAndDynamicInterceptionAdvices ); methodInvocation.proceed(); } }
|
在调用链执行 Advisor通知
时,某些通知内部可能用到 MethodInvocation
调用链对象,注意要添加 proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE)
,将 MethodInvocation
放入当前线程(即外部一个公共的位置),让所有的通知可以获取到 MethodInvocation
调用链对象
调用链实现
间接递归 实现 调用每一个环绕通知以及目标方法 - 责任链模式
动态通知调用
动态通知:有参数绑定的通知,执行时需要获取切点对象来进行参数匹配和绑定吗
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| @Slf4j @SpringBootTest public class SpringAopDynamicTest {
@Aspect static class MyAspect {
@Before("execution(* submit(..)) && args(x)") public void before(int x) { log.info("before:{}", x); } }
static class Target {
public void submit(int x) { log.info("submit:{}", x); } }
@Configuration static class MyConfig {
@Bean public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() { return new AnnotationAwareAspectJAutoProxyCreator(); }
@Bean public MyAspect myAspect() { return new MyAspect(); } }
@Test public void test() throws Throwable { GenericApplicationContext genericApplicationContext = new GenericApplicationContext(); genericApplicationContext.registerBean(ConfigurationClassPostProcessor.class); genericApplicationContext.registerBean(MyConfig.class); genericApplicationContext.refresh();
AnnotationAwareAspectJAutoProxyCreator creator = genericApplicationContext.getBean(AnnotationAwareAspectJAutoProxyCreator.class); List<Advisor> advisors = creator.findEligibleAdvisors(Target.class, "target");
Target target = new Target(); ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(target); proxyFactory.addAdvisors(advisors); Object proxy = proxyFactory.getProxy();
List<Object> interceptorsAndDynamicInterceptionAdvices = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("submit", int.class), Target.class); interceptorsAndDynamicInterceptionAdvices.forEach(o -> log.info("interceptorsAndDynamicInterceptionAdvice:{}", o));
interceptorsAndDynamicInterceptionAdvices.forEach(o -> { try { Class<?> aClass = Class.forName("org.springframework.aop.framework.InterceptorAndDynamicMethodMatcher"); if (aClass.isInstance(o)) { Field interceptor = aClass.getDeclaredField("interceptor"); interceptor.setAccessible(true); Field methodMatcher = aClass.getDeclaredField("methodMatcher"); methodMatcher.setAccessible(true); log.info("InterceptorAndDynamicMethodMatcher对象:{}", o); log.info("interceptor对象:{}", interceptor.get(o)); log.info("methodMatcher对象:{}", methodMatcher.get(o)); }
} catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } }); MethodInvocation methodInvocation = new ReflectiveMethodInvocation( proxy, target, Target.class.getMethod("submit", int.class), new Object[]{100}, Target.class, interceptorsAndDynamicInterceptionAdvices ) { };
methodInvocation.proceed(); } }
|
InterceptorAndDynamicMethodMatcher
属性中包含 环绕通知 和 匹配切点(为了支持动态方法调用)