代理模式
代理模式:(Proxy Pattern),一个类代表另一个类的功能,一般用于对要访问的类做一些控制、功能增强,同时又不想影响原来类的正常业务。
例如:租房子通过中介、找工作通过招聘平台等等。
作用:例如当事人(你)授权代理人(黄牛)办理一些事宜(抢购、抢购等等),无需当事人出面,当事人只和代理人通信。
代理模式使用代理对象完成用户请求,屏蔽用户对真实对象的访问。
代理模式是一种设计模式,在不改变代码的情况下,实现对目标对象的功能扩展,甚至可以对目标对象进行功能覆盖或重写。
静态代理
静态代理:(目标接口、目标接口的实现、代理类),在项目中很少用,但是通过静态代理能够更好的了解动态代理。
测试demo
TargetClass接口
/**
* 目标接口
*/
public interface TargetClass {
public void sayHi();
}
TargetClassImpl接口实现类
public class TargetClassImpl implements TargetClass{
@Override
public void sayHi(){
System.out.println("Hi,静态 proxy");
}
}
ProxyClass代理类
/**
* 代理类:中介
*/
public class ProxyClass implements TargetClass{
private TargetClass targetClass;
public ProxyClass(TargetClassImpl targetClass) {
this.targetClass = targetClass;
}
@Override
public void sayHi() {
//方法调用之前功能增强
System.out.println("方法执行前。。。。。");
targetClass.sayHi();//方法调用
//方法调用之后功能增强
System.out.println("方法执行后。。。。。");
}
}
测试程序
/**
* 静态代理模式
*/
public class Client {
public static void main(String[] args) {
//不使用代理模式
TargetClass targetClass = new TargetClassImpl();
targetClass.sayHi();
System.out.println("------------------------------");
//使用(静态)代理模式
ProxyClass proxyClass = new ProxyClass(new TargetClassImpl());
proxyClass.sayHi();
}
}
结果:
优点:可以实现对目标对象进行修改的前提下,对目标对象进行功能的扩展和增强,也就是扩展原功能,不修改原代码。
缺点:因为代理对象,需要实现与目标对象一样的接口,如果目标接口类繁多,会导致代理类也多,同时一旦接口增加方法,则目标对象和代理类都需要维护。
动态代理
动态代理:(目标接口、目标接口的实现、实现InvocationHandler的调用处理器类)
InvocationHandler是代理实例的调用处理程序实现的接口。在java.lang.reflect下。
每个代理实例都有一个关联的调用处理程序。当在代理实例上调用方法时,方法调用被编码并分派到其调用处理程序的invoke方法
动态代理是利用反射机制在运行时创建代理类。
- 通过实现 InvocationHandler 接口创建自己的调用处理器;
- 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
- 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
- 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
测试demo
TargetClass接口
/**
* 目标接口
*/
public interface TargetClass {
public void sayHi();
}
TargetClassImpl 接口实现类
/**
* 目标接口的实现
*/
public class TargetClassImpl implements TargetClass {
@Override
public void sayHi(){
System.out.println("Hi,动态 proxy");
}
}
ProxyClass 代理类的协助类
/**
* ProxyClass是动态代理的一部分,还不是真正的代理类,协助代理类工作
*/
public class ProxyClass implements InvocationHandler {
private Object target;//目标对象
public ProxyClass() {
}
public ProxyClass(Object target) {
this.target = target;
}
/**
* 该方法在目标的方法被执行的时候,被调用
* 在调用目标方法时,会先调用invoke方法
* @param proxy 代理类
* @param method 目标方法
* @param args 代表目标方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法调用之前功能增强
System.out.println("目标方法执行前。。。。。");
Object result = method.invoke(target,args);//该方法真正调用目标方法
//方法调用之后功能增强
System.out.println("目标方法执行后。。。。。");
return result;
}
}
测试程序
/**
* 动态代理
*/
public class Client {
public static void main(String[] args) {
//不使用代理模式
TargetClass targetClass = new TargetClassImpl();
targetClass.sayHi();
System.out.println("------------------------------");
//使用动态代理
/**
* 该方法三个参数
* 第一个:为定义代理类的类加载器,这里可以使用当前类的加载器,或者使用接口的类加载器
* (类.class.getClassLoader())获取该类的类加载器
* 第二个:代理类要实现的接口列表,是一个数组。
* 第三个:InvocationHandler,调用处理器,将方法调用分派到的调用处理程序,需要把实现类传给协助代理类的类调用invoke方法里
* 也就是说要传一个实现类给协助类,在协助类里有一个目标成员通过构造方法传参。
* 返回结果是真正的一个代理类Object类型,该代理类由指定的类加载器定义并实现指定的接口
*/
TargetClass targetClass1 = (TargetClass) Proxy.newProxyInstance(TargetClass.class.getClassLoader(),
new Class<?>[]{TargetClass.class}, new ProxyClass(new TargetClassImpl()));
targetClass1.sayHi();
}
}
结果