动态代理

简介

Spring AOP实现原理是java语言的动态代理,学习后写篇日记记录下来!

原理

java动态代理的原理为:使用java反射生成与委托类相同接口的代理类,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

Java反射

java反射主要涉及的是java.lang.Class、java.lang.reflect.Constructor、java.lang.reflect.Field、java.lang.reflect.Method等类。下面的demo来演示反射的一些基本使用方法:

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.demo.proxy;

/**
* Created by 程祥 on 15/12/30.
* Function:学习反射用的model
*/

public class ReflectModel {
//省略get、set方法
private String string;
//此处为public
public int num;
private String[] arr;

public void voidMethod(String arg){
System.out.println("voidMethod********"+arg);
}

public String argMethod(String arg){
System.out.println(arg);
return arg+"******argMethod";
}


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

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
* Created by 程祥 on 15/12/30.
* Function:反射学习测试
*/

public class ReflectTest {


public static void main(String[] args){
try {
Class reflectClass = Class.forName("com.demo.proxy.ReflectModel");
//此处相当于 new ReflectModel();
ReflectModel reflectObj = (ReflectModel)reflectClass.newInstance();
//可以正常输出
reflectObj.voidMethod("reflectObj");

Constructor constructor = reflectClass.getConstructor();
ReflectModel constructorObj = (ReflectModel)constructor.newInstance();
//可以正常输出
reflectObj.voidMethod("constructorObj");

Method voidMethod = reflectClass.getMethod("voidMethod",String.class);
voidMethod.invoke(constructorObj, "methodInvoke");
Method arrMthod = reflectClass.getMethod("setArr",String[].class);
String[] arrStr = {"aaa","bb"};

//arrStr前面需要加Object转型,
//不然会报错java.lang.IllegalArgumentException:Wrong number of arguments
arrMthod.invoke(constructorObj, (Object) arrStr);
System.out.println(Arrays.toString(constructorObj.getArr()));

Method setNum = reflectClass.getMethod("setNum",int.class);
setNum.invoke(constructorObj,100);
//都需要考虑访问性 private/protect/public
Field numField = reflectClass.getField("num");
System.out.println(numField.getInt(constructorObj));

} catch (InstantiationException e) {

e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}

}

Java动态代理

动态代理使用java反射生成与委托类相同接口的代理类,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。原理如上图,demo如下:

1
2
3
4
5
package com.demo.proxy;

public interface TestService {
void printText();
}
1
2
3
4
5
6
7
8
9
package com.demo.proxy.impl;

import com.demo.proxy.TestService;

public class TestServiceImpl implements TestService {
public void printText() {
System.out.println("*****TestServiceImpl******");
}
}
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
package com.demo.proxy.impl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxySubject implements InvocationHandler {

//被代理对象
private Object object;

public ProxySubject(Object object) {
this.object = object;
}

public Object getProxyBean(){
//返回代理对象
return Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(), this);
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//代理增强
System.out.println("InvokeImpl proxy add function~");
//使用反射
Object result = method.invoke(object, args);
System.out.println(proxy.getClass().getName());
//。。。some other function
return result;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.demo.proxy;

import com.demo.proxy.impl.ProxySubject;
import com.demo.proxy.impl.TestServiceImpl;
import java.lang.reflect.Proxy;

public class Client {


public static void main(String[] args){
TestService service = new TestServiceImpl();
ProxySubject invoke = new ProxySubject(service);
TestService proxy = (TestService)invoke.getProxyBean();
//实现功能与正常实现类一样,并添加了相应增强功能
proxy.printText();
}

}

结语

java反射功能非常强大,用处特别多。动态代理和CGLIB的区别是动态代理使用于接口模式下,CGLIB使用于类与类之间的继承,CGLIB新生成了一个继承自原类的子类,CGLIB不适用与被final修饰的类进行代理。