2019-1-14
- 实现动态代理的前期准备:
- 一个接口
Person
; - 一个接口实现类
Student
,即被代理类; - 一个
InvocationHandler
实现类MyInvocationHandler
。
- 一个接口
- 动态代理原理及过程:
- 将被代理类对象
student
的引用交给MyInvocationHandler
; - 使用
Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces)
方法获取一个动态代理类proxyClass
,这个proxyClass
实现了传入的所有接口,这里的ClassLoader
是系统类加载器,所以使用任意类的ClassLoader
都一样的; - 使用
proxyClass.getConstructor(Class<?>... parameterTypes)
获取其构造函数constructor
; - 将
myInvocationHandler
对象传入constructor.newInstance(Object... initargs)
获取动态代理类对象proxy
,并强转为Person
类型; - 调用动态代理类对象
proxy
的方法,将调用myInvocationHandler
的invoke()
方法,在invoke()
方法内则调用被代理对象的对应方法,实现动态代理。 - 第2、3、4步可以合并为一步,
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
。
- 将被代理类对象
- 例子
- 静态代理
接口:
public interface Person {
void say();
}
被代理类:
public class Student implements Person {
private String name;
public String getName() {
return name;
}
public Student setName(String name) {
this.name = name;
return this;
}
@Override
public void say() {
System.out.println(name + " say : hello");
}
}
代理类:
public class StudentProxy implements Person {
/**
* 被代理对象
*/
private Student student;
public StudentProxy(Student student) {
this.student = student;
}
@Override
public void say() {
student.say();
}
}
执行代理:
public static void main(String[] args) {
// 初始化被代理类
Student student = new Student().setName("小明");
// 初始化代理类
StudentProxy studentProxy = new StudentProxy(student);
// 代理类执行方法
studentProxy.say();
}
这里的静态代理的感觉其实和装饰器模式有点类似,内置了一个对象,外层和内层都实现了相同的接口或继承了相同的父类,在调用外层对象的方法时,实际上是调用了内层对象的方法。
- 动态代理
接口和接口实现类依然使用上面的Person和Student,我们还缺少一个InvocationHandler的实现类MyInvocationHandler。
MyInvocationHandler:
public class MyInvocationHandler<T> implements InvocationHandler {
/**
* 被代理对象
*/
private T element;
public MyInvocationHandler(T element) {
this.element = element;
}
/**
* @author yc 2019年1月14日
* @param proxy
* 指代我们所代理的那个真实对象
* @param method
* 指代的是我们所要调用真实对象的某个方法的Method对象
* @param args
* 指代的是调用真实对象某个方法时接受的参数
* @return
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强。。。
Object result = method.invoke(element, args);
// 后置增强。。。
return result;
}
}
执行动态代理:
@SuppressWarnings("unchecked")
public class DynamicProxy<T> {
private Class<T> clazz;
public DynamicProxy() {
this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
/**
* 方法一
*
* @author yc 2019年1月14日
* @param myInvocationHandler
* @return
*/
public T one(InvocationHandler myInvocationHandler) throws NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 生成一个动态代理类
Class<?> proxyClass = Proxy.getProxyClass(clazz.getClassLoader(), new Class<?>[] { clazz });
// 获取动态代理类的构造器
Constructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class);
// 获取代理对象
return (T) constructor.newInstance(myInvocationHandler);
}
/**
* 方法二
*
* @author yc 2019年1月14日
* @return
*/
public T two(InvocationHandler myInvocationHandler) {
/**
* Proxy这个类的作用就是用来动态创建一个代理对象的类<br>
* loader:
* 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载。这里使用的类加载器应该都是系统类加载器,所以使用哪个Class获取都一样<br>
* interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了<br>
* h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
*/
return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] { clazz }, myInvocationHandler);
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 被代理对象
Student student = new Student().setName("小明");
// 代理类与被代理类的中间类
MyInvocationHandler<Student> myInvocationHandler = new MyInvocationHandler<Student>(student);
// 注意这里的{},必须使用匿名内部类,否则获取到的超类为Object,会出现类型转换错误
Person person = (new DynamicProxy<Person>() {
}).one(myInvocationHandler);
person.say();
person = (new DynamicProxy<Person>() {
}).two(myInvocationHandler);
person.say();
}
}
可以看到,在动态代理里面我并没有使用StudentProxy
类,而是通过MyInvocationHandler
类动态地使用Method
类对象去执行相应的方法。