AOP
# AOP增强方式
aspectj 编译器增强;
通过 ajc 编译器在编译 class 类文件时,就把通知的增强功能,织入到目标类的字节码中;
通过 agent 在加载目标类时,修改目标类的字节码,织入增强功能;
代理增强 (运行期增强);
jdk动态代理:目标必须实现接口,生成的代理类实现相同接口,因此代理与目标之间是平级兄弟关系;
public class JdkProxyDemo { interface Foo{ void foo(); } //目标类与代理是兄弟关系 static class Target implements Foo{ @Override public void foo() { System.out.println("target foo"); } } public static void main(String[] param) { //目标对象 Target target = new Target(); //代理对象 (1.目标对象的类加载器,2.接口,3.InvocationHandler) Foo proxy = (Foo) Proxy.newProxyInstance(Target.class.getClassLoader(), new Class[]{Foo.class}, //1.代理对象自己,2.正在执行的方法,3.方法传过来的实际参数 (p,method,args)->{ System.out.println("Proxy before..."); // 一般调用方法:目标.方法(参数); // 使用反射:方法.invoke(目标,参数); Object res = method.invoke(target,args); System.out.println("Proxy after..."); return res; }); //调用代理 proxy.foo(); } }
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
31cglib动态代理:生成的代理类是目标的子类,因此代理与目标之间是子父关系;
public class CglibProxyDemo { static class Target { public void foo() { System.out.println("target foo"); } } public static void main(String[] param) { Target target = new Target(); // 代理和目标是父子继承关系 Target proxy = (Target) Enhancer.create(Target.class, new MethodInterceptor() { // 1.代理对象自己,2.代理类中执行的方法,3.方法参数,4.另一个方法对象 @Override public Object intercept(Object p, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before..."); // Object res = method.invoke(target,args);// 用方法反射调用目标 // //methodProxy 避免反射调用 // Object res = methodProxy.invoke(target,args); // 内部没有用反射,需要目标(Spring使用); Object res = methodProxy.invokeSuper(p,args);// 内部没有用反射,需要代理; System.out.println("after..."); return res; } }); proxy.foo(); } }
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
# jdk代理原理
利用 InvocationHandler回调;
接口与目标类
public interface Foo { void foo(); int bar(); }
1
2
3
4public class Target implements Foo{ @Override public void foo() { System.out.println("target foo"); } @Override public int bar() { System.out.println("target bar"); return 100; } }
1
2
3
4
5
6
7
8
9
10
11
12代理类
public class $Proxy0 implements Foo{ private A2.InvocationHandler h; public $Proxy0(A2.InvocationHandler h){ this.h = h; } static Method foo;//避免调用一次就创建一个方法对象 static Method bar; static { try { foo = Foo.class.getMethod("foo"); bar = Foo.class.getMethod("bar"); } catch (NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } } @Override public void foo() { try { h.invoke(this,foo,new Object[0]);//代理类为自己this } catch (RuntimeException | Error e) {//运行时异常 直接抛 throw e; } catch (Throwable e) {//检查异常 转换未运行异常 throw new UndeclaredThrowableException(e); } } @Override public int bar() { try { Object result = h.invoke(this, bar, new Object[0]); return (int) result; } 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
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测试
public class A2 { interface InvocationHandler { Object invoke(Object proxy,Method method,Object[] args) throws Throwable; } public static void main(String[] param) { Foo proxy = new $Proxy0(new InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ // 1.动态增强 System.out.println("before..."); // 2.反射调用目标方法 return method.invoke(new Target(),args); } }); proxy.foo(); proxy.bar(); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
如果直接将代理类继承Proxy类,省去自己定义InvocationHandler过程;
public class $Proxy0 extends Proxy implements Foo{ // private A2.InvocationHandler h; // // public $Proxy0(A2.InvocationHandler h){ // this.h = h; // } protected $Proxy0(InvocationHandler h) { super(h); } //...... }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class A2 { // interface InvocationHandler { // Object invoke(Object proxy,Method method,Object[] args) throws Throwable; // } public static void main(String[] param) { Foo proxy = new $Proxy0(new InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ // 1.动态增强 System.out.println("before..."); // 2.反射调用目标方法 return method.invoke(new Target(),args); } }); proxy.foo(); proxy.bar(); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# cglib代理原理
利用 MethodInterceptor回调;
使用 MethodProxy避免反射;
目标类
public class Target { public void save() { System.out.println("save()"); } public void save(int i) { System.out.println("save(int)"); } public void save(long j) { System.out.println("save(long)"); } }
1
2
3
4
5
6
7
8
9
10
11
12
13代理类
public class Proxy extends Target{ private MethodInterceptor methodInterceptor; public void setMethodInterceptor(MethodInterceptor methodInterceptor) { this.methodInterceptor = methodInterceptor; } static Method save0; static Method save1; static Method save2; static MethodProxy save0Proxy; static MethodProxy save1Proxy; static MethodProxy save2Proxy; static { try { save0 = Target.class.getMethod("save"); save1 = Target.class.getMethod("save", int.class); save2 = Target.class.getMethod("save", long.class); save0Proxy = MethodProxy.create(Target.class, Proxy.class, "()V", "save", "saveSuper"); save1Proxy = MethodProxy.create(Target.class, Proxy.class, "(I)V", "save", "saveSuper"); save2Proxy = MethodProxy.create(Target.class, Proxy.class, "(J)V", "save", "saveSuper"); } catch (NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } } // 原始功能 public void saveSuper() { super.save(); } public void saveSuper(int i) { super.save(i); } public void saveSuper(long j) { super.save(j); } // 增强功能 @Override public void save() { try { methodInterceptor.intercept(this, save0, new Object[0], save0Proxy); } catch (Throwable e) { throw new UndeclaredThrowableException(e); } } @Override public void save(int i) { try { methodInterceptor.intercept(this, save1, new Object[]{i}, save1Proxy); } catch (Throwable e) { throw new UndeclaredThrowableException(e); } } @Override public void save(long j) { try { methodInterceptor.intercept(this, save2, new Object[]{j}, save2Proxy); } catch (Throwable e) { throw new UndeclaredThrowableException(e); } } }
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测试
public class A3 { public static void main(String[] args) { Proxy proxy = new Proxy(); Target target = new Target(); proxy.setMethodInterceptor(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before..."); // 反射调用 // return method.invoke(target, args); // 内部无反射, 结合目标用 return methodProxy.invoke(target, args); // 内部无反射, 结合代理用 // return methodProxy.invokeSuper(p, args); } }); proxy.save(); proxy.save(1); proxy.save(2L); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Spring选择代理
Spring 中对切点、通知、切面的抽象:
- 切点:接口 Pointcut,典型实现 AspectJExpressionPointcut;
- 通知:典型接口为 MethodInterceptor 代表环绕通知;
- 切面:Advisor,包含一个 Advice 通知,PointcutAdvisor 包含一个 Advice 通知和一个 Pointcut;
代理类相关:
- AopProxyFactory 根据 proxyTargetClass 等设置选择 AopProxy 实现;
- AopProxy 通过 getProxy 创建代理对象;
- 调用代理方法时,会借助 ProxyFactory 将通知统一转为环绕通知:MethodInterceptor;
测试:
public class A4 {
public static void main(String[] args) {
/*
两个切面概念
aspect =
通知1(advice) + 切点1(pointcut)
通知2(advice) + 切点2(pointcut)
通知3(advice) + 切点3(pointcut)
...
advisor = 更细粒度的切面,包含一个通知和切点
*/
// 1. 备好切点
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* foo())");
// 2. 备好通知
MethodInterceptor advice = invocation -> {
System.out.println("before...");
Object result = invocation.proceed(); // 调用目标
System.out.println("after...");
return result;
};
// 3. 备好切面
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
/*
4. 创建代理
a. proxyTargetClass = false, 目标实现了接口, 用 jdk 实现
b. proxyTargetClass = false, 目标没有实现接口, 用 cglib 实现
c. proxyTargetClass = true, 总是使用 cglib 实现
*/
Target2 target = new Target2();
ProxyFactory factory = new ProxyFactory();
factory.setTarget(target);
factory.addAdvisor(advisor);
factory.setInterfaces(target.getClass().getInterfaces());
factory.setProxyTargetClass(false);
Target2 proxy = (Target2) factory.getProxy();
System.out.println(proxy.getClass());
proxy.foo();
proxy.bar();
}
interface I1 {
void foo();
void bar();
}
static class Target1 implements I1 {
public void foo() {
System.out.println("target1 foo");
}
public void bar() {
System.out.println("target1 bar");
}
}
static class Target2 {
public void foo() {
System.out.println("target2 foo");
}
public void bar() {
System.out.println("target2 bar");
}
}
}
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
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
# 从@Aspect到Advisor
代理创建器:AnnotationAwareAspectJAutoProxyCreator 的作用
将高级 @Aspect 切面统一为低级 Advisor 切面;
在合适的时机创建代理(Bean的实例化与依赖注入间,或初始化之后);
代理创建时机:
- 初始化之后 (无循环依赖时);
- 实例创建后, 依赖注入前 (有循环依赖时), 并暂存于二级缓存;
public class A1 {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("aspect1", Aspect1.class);
context.registerBean("config", Config.class);
context.registerBean(ConfigurationClassPostProcessor.class);
context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);//Bean后处理器
context.refresh();
/*
第一个重要方法 findEligibleAdvisors 找到有【资格】的 Advisors
a. 有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如下例中的 advisor3
b. 有【资格】的 Advisor 另一部分是高级的, 由本章的主角解析 @Aspect 后获得
*/
AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
List<Advisor> advisors = creator.findEligibleAdvisors(Target2.class, "target2");
for (Advisor advisor : advisors) {
System.out.println(advisor);
}
/*
第二个重要方法 wrapIfNecessary
a. 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理
*/
Object o1 = creator.wrapIfNecessary(new Target1(), "target1", "target1");
System.out.println(o1.getClass());
Object o2 = creator.wrapIfNecessary(new Target2(), "target2", "target2");
System.out.println(o2.getClass());
((Target1) o1).foo();
}
static class Target1 {
public void foo() {
System.out.println("target1 foo");
}
}
static class Target2 {
public void bar() {
System.out.println("target2 bar");
}
}
@Aspect // 高级切面类
static class Aspect1 {
@Before("execution(* foo())")
public void before1() {
System.out.println("aspect1 before1...");
}
@Before("execution(* foo())")
public void before2() {
System.out.println("aspect1 before2...");
}
}
@Configuration
static class Config {
@Bean // 低级切面
public Advisor advisor3(MethodInterceptor advice3) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* foo())");
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice3);
return advisor;
}
@Bean
public MethodInterceptor advice3() {
return invocation -> {
System.out.println("advice3 before...");
Object result = invocation.proceed();
System.out.println("advice3 after...");
return result;
};
}
}
}
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
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
高级切面@Before如何转化为低级切面?
public class A2 { static class Aspect { @Before("execution(* foo())") public void before1() { System.out.println("before1"); } @Before("execution(* foo())") public void before2() { System.out.println("before2"); } public void after() { System.out.println("after"); } public void afterReturning() { System.out.println("afterReturning"); } public void afterThrowing() { System.out.println("afterThrowing"); } public Object around(ProceedingJoinPoint pjp) throws Throwable { try { System.out.println("around...before"); return pjp.proceed(); } finally { System.out.println("around...after"); } } } static class Target { public void foo() { System.out.println("target foo"); } } @SuppressWarnings("all") public static void main(String[] args) throws Throwable { AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new Aspect()); // 高级切面转低级切面类 List<Advisor> list = new ArrayList<>(); for (Method method : Aspect.class.getDeclaredMethods()) { if (method.isAnnotationPresent(Before.class)) { // 解析切点 String expression = method.getAnnotation(Before.class).value();//切点表达式 AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression(expression);//创建切点对象 // 通知类,根据注解的不同选择不同的底层实现,如@Before AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory); // 切面 Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice); list.add(advisor); } } for (Advisor advisor : list) { System.out.println(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
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
@Before 前置通知会被转换为原始的 AspectJMethodBeforeAdvice 形式,该对象包含了如下信息:
- 通知代码从哪儿来;
- 切点是什么(这里为啥要切点, 后面解释);
- 通知对象如何创建, 本例共用同一个 Aspect 对象;
类似的还有
- AspectJAroundAdvice (环绕通知);
- AspectJAfterReturningAdvice;
- AspectJAfterThrowingAdvice (环绕通知);
- AspectJAfterAdvice (环绕通知);
通知统一转换为环绕通知 MethodInterceptor;