动态代理是在实现阶段不用关心代理谁,而在运行阶段 才指定代理哪一个对象。相对来说,自己写代理类的方式就是静态代理。本章节的核心部分 就在动态代理上,现在有一个非常流行的名称叫做面向横切面编程,也就是AOP(Aspect Oriented Programming),其核心就是采用了动态代理机制。
原理
通过用户实现的InvocationHandler接口,获得真实处理事件的对象(相当于Proxy加了个传入真实实现对象监听);
通过newProxyInstance传入的ClassLoader和一组Interface来创建动态代理类;
通过反射获取动态代理类的构造方法,其构造函数的参数就是用户实现的InvocationHandler接口类;
通过构造函数创建动态代理类实例。
优点:能够动态适配特定的代理场景,扩展性较好,符合软件工程的开闭原则
缺点:动态代理需要利用到反射机制和动态生成字节码,导致其性能会比静态代理稍差一些,但是相比于优点,这些劣势几乎可以忽略不计
java中动态代理主要依靠InvocationHandler这个接口以及Proxy这个类的方法来实现。
动态代理是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
动态代理解决的问题是面对新的需求时,不需要修改代理对象的代码,只需要新增接口和真实对象,在客户端调用即可完成新的代理。
这样做的目的:满足软件工程的开闭原则,提高类的可维护性和可扩展性。
代码块
public interface ITeacherDap {
void teacher();
}
public class TeacherDao implements ITeacherDap{
@Override
public void teacher() {
System.out.println("老师正在授课");
}
}
public class ProxyFactory {
//维护目标对象,object
private Object target;
//构造器,并且初始化target
public ProxyFactory(Object target) {
super();
this.target = target;
}
//给目标对象,生成代理对象
public Object getProxyInstance() {
/*
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
*/
//ClassLoader loader指定当前目标对象使用的类加载器,获取加载器的方法固定
// Class<?>[] interfaces目标对象的实现的接口类型,使用泛型方法确认类型
//InvocationHandler h 事情处理,执行目标对象的方法时,触发事情处理方法,
//会把当前执行的对象方法作为参数传入
//loader
//interfaces
//h
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInt erfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("jdk代理开始");
//通过反射机制调用目标对象的反射方法
Object returnVal = method.invoke(target, args);
System.out.println("jdk代理提交");
return returnVal;
}
});
}
}
public class Clients {
public static void main(String[] args) {
//创建目标对象
ITeacherDap target = new TeacherDao();
//给目标对象创建代理对象,转成ITeacherDap
ITeacherDap p = (ITeacherDap)new ProxyFactory(target).getProxyInstance();
//proxyinstance=class com.sun.proxy.$Proxy0内存中动态生成代理对象
System.out.println("proxyinstance="+p.getClass());
p.teacher();
}
}