动态代理

1、基本概念

  • 代理

    指以他人的名义,在授权范围内进行对被代理人直接发生法律效力的法律行为。

  • 静态代理

    指由人创建或者工具生成的代理类,这个类在编译期就已经存在的。

  • 动态代理

    指代理类在编译期不存在,是在程序运行中自动生成的。

2、动态代理分类

  1. JDK动态代理

    基于java的反射机制并实现目标类的接口,动态生成代理类调用目标类的方法。

  2. CGLIB 动态代理

    基于继承目标类生成代理子类,不需要实现接口,只需要目标类是非final类即可。(底层是借助asm字节码技术)

  3. AspectJ 动态代理

    基于修改目标类的字节,织入代理的字节,在程序编译的时候插入动态代理的字节码,不会生成全新的Class。

3、例子

3.1、JDK动态代理

  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
public interface CalculateService {

/**
* 加法计算
* @param one
* @param two
* @return
*/
public int add(int one,int two);

/**
* 减法计算
* @param one
* @param two
* @return
*/
public int sub(int one,int two);

/**
* 乘法计算
* @param one
* @param two
* @return
*/
public int mul(int one,int two);

/**
* 除法计算
* @param one
* @param two
* @return
*/
public int div(int one,int two);

}
  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
public class CalculateServiceImpl implements CalculateService{

/**
* 加法计算
* @param one
* @param two
* @return
*/
public int add(int one,int two){
int result = one + two;
return result;
}

/**
* 减法计算
* @param one
* @param two
* @return
*/
public int sub(int one,int two){
int result = one - two;
return result;
}

/**
* 乘法计算
* @param one
* @param two
* @return
*/
public int mul(int one,int two){
int result = one * two;
return result;
}

/**
* 除法计算
* @param one
* @param two
* @return
*/
public int div(int one,int two){
int result = one / two;
return result;
}

}
  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
public class MyProxy {
//1、获取目标对象
private Object target;

public MyProxy(Object target) {
this.target = target;
}

//2、生成代理对象
public Object getProxy() {

//2.1、生成代理对象
Object proxy;

/**
* loader:ClassLoader对象。类加载器对象,用于加载动态生成的代理类。
* interfaces:接口数组,提供目标对象的所有接口,目的是让代理对象保证与目标对象都有接口中相同的方法。
* h:InvocationHandler类型的对象。
*/
ClassLoader loader = target.getClass().getClassLoader();

Class [] interfaces = target.getClass().getInterfaces();

proxy = Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {

/**
* 代理对象调用代理方法,在其中调用目标对象的方法
*
* proxy:代理对象,在invoke方法中一般不会使用
*
* method:目标对象要被调用的方法对象
*
* args:目标对象要被调用的方法的参数
*
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

//获取方法名称
String name = method.getName();

//在方法调用前进行日志记录
System.out.println("方法" + name + "传入参数为:" + Arrays.asList(args) + ",执行开始");

//执行方法
Object result = method.invoke(target, args);

//在方法调用后进行日志记录
System.out.println("方法" + name + "执行结果:" + result);
return result;
}
});
return proxy;
}
}
  1. 主方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Main {

public static void main(String[] args) throws Exception {
// 代理类class文件存入本地磁盘方便我们反编译查看源码
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

//创建目标对象
CalculateServiceImpl target = new CalculateServiceImpl();

//通用的代理
CalculateService proxy = (CalculateService)new MyProxy(target).getProxy();

//执行方法
int result = proxy.add(1, 2);
System.out.println(result);
}
}

3.2、CGLIB 动态代理

  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
public class CalculateService{

/**
* 加法计算
* @param one
* @param two
* @return
*/
public int add(int one,int two){
int result = one + two;
return result;
}

/**
* 减法计算
* @param one
* @param two
* @return
*/
public final int sub(int one,int two){
int result = one - two;
return result;
}

/**
* 乘法计算
* @param one
* @param two
* @return
*/
public int mul(int one,int two){
int result = one * two;
return result;
}

/**
* 除法计算
* @param one
* @param two
* @return
*/
public int div(int one,int two){
int result = one / two;
return result;
}

}
  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
public class MyMethodInterceptor implements MethodInterceptor {

/**
* 方法拦截
*
* obj:cglib生成的代理对象
*
* method:目标对象要被调用的方法对象
*
* args:目标对象要被调用的方法参数
*
* MethodProxy:代理方法
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//获取方法名称
String name = method.getName();

//在方法调用前进行日志记录
System.out.println("方法" + name + "传入参数为:" + Arrays.asList(args) + ",执行开始");

//执行方法
Object result = proxy.invokeSuper(obj, args);

//在方法调用后进行日志记录
System.out.println("方法" + name + "执行结果:" + result);
return result;
}

}
  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
public class Main {

public static void main(String[] args) {
// 代理类class文件存入本地磁盘方便我们反编译查看源码
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\proxy\\cglib");

//通过CGLIB动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
//设置enhancer对象的父类
enhancer.setSuperclass(CalculateService.class);
//设置enhancer的回调对象
enhancer.setCallback(new MyMethodInterceptor());
//创建代理对象
CalculateService proxy = (CalculateService) enhancer.create();
//通过代理对象调用目标方法
int result = proxy.add(1, 2);
System.out.println(result);

//注意:类或者方法为final的修饰的没办法进行代理
result = proxy.sub(2, 1);
System.out.println(result);

}
}