ZB-046-02AOP两种实现

AOP两种实现

上一篇仍然有很多不足,如 DataService 每个方法打日志,依然需要在 LogDecorator.java里每个功能都写一遍

能不能一进来的时候,所有方法进入和进出的时候都打印日志

一个疑问为什么 DataService 定义为接口(interface)而不是类(Class)

  • 接口定义了一个虚拟的协议/合同/合约
  • 变成了class咋样?
    • 每个东西继承它的时候,假设你要用抽象类有很多成员变量就会有多余的无用变量

AOP的实现

JDK的动态代理

新建 LogProxy.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LogProxy implements InvocationHandler {
DataService delegate;

public LogProxy(DataService delegate) {
this.delegate = delegate;
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + "is start,params is " + Arrays.toString(args));
Object returnValue = method.invoke(delegate,args);
System.out.println(method.getName() + "is finised");
return returnValue;
}
}

Main.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.aop.demo;

import java.lang.reflect.Proxy;

public class Main {
static DataService service = new LogDecorator(new DataServiceImpl());

static DataService service2 = new DataServiceImpl();

public static void main(String[] args) {
// OOP装饰器模式
System.out.println(service.a(1));
System.out.println(service.b(1));

// 动态代理
DataService dataService = (DataService) Proxy.newProxyInstance(service2.getClass().getClassLoader(), // 接口实现类
new Class[]{DataService.class}, // 代理类(必须是接口否则报错)
new LogProxy(service2) // 这个方法拦截后被谁处理
);

dataService.a(1);
dataService.b(2);
}
}

一个问题,我想要用类实现这个功能,而不是接口怎么办?

  • CGLIB/ByteBuddy 字节码生成
    • 优点:强大,不受接口的限制
    • 缺点:需要引入额外的第三方类库
      • 不能增强 final 类/final/ private方法 因为他用的继承的方式实现这些功能的

它们的本质,就是动态的class,没有具体的说明书,JDK直接通过字节码操作

google 搜索cglib methodinterceptor maven

pom.xml里添加

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>

新建 DataServiceImpl2.java 注意这次是 类而不是接口了

1
2
3
4
5
6
7
8
9
public class DataServiceImpl2 {
public String a(int i) {
return UUID.randomUUID().toString();
}

public String b(int i) {
return UUID.randomUUID().toString();
}
}

新建LogInterceptor.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LogInterceptor implements MethodInterceptor {
private DataServiceImpl2 delegate;

public LogInterceptor(DataServiceImpl2 delegate) {
this.delegate = delegate;
}

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(method.getName() + " is start,params is " + Arrays.toString(objects));
Object returnValue = method.invoke(delegate,objects);
System.out.println(method.getName() + " is finised");
return returnValue;
}
}

Main.java

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
package com.aop.demo;

import net.sf.cglib.proxy.Enhancer;
import java.lang.reflect.Proxy;

public class Main {
static DataService service = new LogDecorator(new DataServiceImpl());

// AOP动态代理
static DataService service2 = new DataServiceImpl();

public static void main(String[] args) {
// OOP装饰器模式
System.out.println(service.a(1));
System.out.println(service.b(1));

System.out.println("动态代理-----------------");
// 动态代理
DataService dataService = (DataService) Proxy.newProxyInstance(service2.getClass().getClassLoader(), // 接口实现类
new Class[]{DataService.class}, // 代理类(必须是接口否则报错)
new LogProxy(service2) // 这个方法拦截后被谁处理
);

dataService.a(1);
dataService.b(2);

// AOP 动态字节码
System.out.println("动态字节码-----------------");
// 动态字节码增强
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(DataServiceImpl2.class);// 设置超类
enhancer.setCallback(new LogInterceptor(new DataServiceImpl2())); // 设置回调

// 使用动态字节码增强过的
DataServiceImpl2 enhancedService = (DataServiceImpl2) enhancer.create();
enhancedService.a(1);
enhancedService.b(2);
}
}

代码链接

https://github.com/slTrust/java-aop-demo