代理模式
代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式的思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。
代理模板一般有两种:
- 静态代理:由程序员创建或工具生成代理类的源码,再编译代理类,即代理类和委托类的关系再程序运行前就已经存在。
- 动态代理:在运行期间使用动态生成字节码形式,动态创建代理类。使用的工具有 jdkproxy、cglibproxy 等。
AOP的原理就是动态代理机制。RPC框架也是实现了AOP机制。
静态代理
静态代理的好处:
- 可以隐藏委托类的具体实现;
- 可以在不改变委托类的情况下增加额外的操作。
静态代理:在代码编译时就确定了被代理的类是哪一个(编译的时候就生成代理类的字节码文件)
静态代理比较简单,代理类和被代理类实现了同一接口,在代理类的构造函数中定义一个被代理类的对象即可。
动态代理
动态代理常用的有jdk动态代理与cglib动态代理
- jdk动态代理,必须实现InvocationHandler,重写invoke方法
- cglib动态代理,不满足以上条件的动态代理一般都是采用cglib,需要导入相应的jar包
主要是介绍一下jdk动态代理:
java的jdk动态代理机制中,有两个重要的类或者接口,一个是InvocationHandler(Interface),还有一个是Proxy(是一个class)。
- InvocationHandler是每一个动态代理类都必须要实现的接口,我们通过代理对象调用一个方法的时候,该方法就会被转发由InvocationHandler这个接口的invoke方法来调用。
- Proxy类,动态的创建一个代理对象的类,它提供了许多方法,我们用的最多的是newProxyInstance方法,该方法的作用就是得到一个动态的代理对象。
JDK动态代理模式主要由四个元素共同组成:
1.接口:定义具体实现的方法
2.被代理类:实现上述接口,执行接口中的方法
3.代理类:实现InvocationHandler,帮助被代理类实现方法。
代理类中要实现的内容有:
因为动态代理不知道被代理的类是哪一个,所以在实现了InvocationHandler的代理类中定义了一个Object类,在代理类的构函数中作为参数传递进来。
实现InvocationHandler中的invoke方法。
写main方法,并在main方法中根据定义的被代理类实现代理类的生成。
动态代理的步骤:
- 首先获得一个被代理对象的引用,
- 获得该引用的接口
- 生成一个类,这个类实现了我们给的代理对象所实现的接口
- 上述类编译生成了.class字节码供JVM使用
- 调用上述生成的class
/**
* 动态代理类
* @author Martina
*
*/
public class MyInvocationHandler implements InvocationHandler{
private Object object;
public MyInvocationHandler(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("MyInvocationHandler invoke begin");
System.out.println("proxy: "+ proxy.getClass().getName());
System.out.println("method: "+ method.getName());
for(Object o : args){
System.out.println("arg: "+ o);
}
//通过反射调用 被代理类的方法
method.invoke(object, args);
System.out.println("MyInvocationHandler invoke end");
return null;
}
public static void main(String [] args){
//创建需要被代理的类
Student s = new Student();
//这一句是生成代理类的class文件,前提是你需要在工程根目录下创建com/sun/proxy目录,不然会报找不到路径的io异常
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
//获得加载被代理类的 类加载器
ClassLoader loader = Thread.currentThread().getContextClassLoader();
//指明被代理类实现的接口
Class<?>[] interfaces = s.getClass().getInterfaces();
// 创建被代理类的委托类,之后想要调用被代理类的方法时,都会委托给这个类的invoke(Object proxy, Method method, Object[] args)方法
MyInvocationHandler h = new MyInvocationHandler(s);
//生成代理类
//注意newProxyInstance的三个参数所代表的含义
Person proxy = (Person)Proxy.newProxyInstance(loader, interfaces, h);
//通过代理类调用 被代理类的方法
proxy.sayHello("yujie.wang", 20);
proxy.sayGoodBye(true, 100);
System.out.println("end");
}
}