为对象提供一种代理,以控制对这个对象的访问。(中介)
为什么要用代理模式?
- 中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
- 开闭原则,增加功能 增加功能,不需要修改委托类,例如缓存,日志功能
应用场景:
想在访问一个类时做一些控制
应用实例:
1.windows 快捷方式 2.Spring aop
静态代理
public interface BuyHouse {
void buyHouse();
}
/**
* 委托类
*
* @author wuhongyun
* @date 2020/4/15 0:12
*/
public class BuyHouseImpl implements BuyHouse {
private String name;
public BuyHouseImpl(String name) {
this.name = name;
}
@Override
public void buyHouse() {
System.out.println(name + "掏钱买房");
}
}
/**
* 静态代理
* 在构造函数中把将委托对象传过去,重写接口方法(添加代码,调用委托类的代码)
*
* @author wuhongyun
* @date 2020/4/15 0:13
*/
public class BuyHouseStaticProxy implements BuyHouse {
/**
* 代理对象和被代理对象 共同实现的 接口类
*/
private BuyHouse buyHouse;
public BuyHouseStaticProxy(BuyHouse buyHouse1) {
this.buyHouse = buyHouse1;
}
@Override
public void buyHouse() {
System.out.println("买房准备");
buyHouse.buyHouse();
System.out.println("买房装修");
}
}
/**
* 客户类
*
* @author wuhongyun
* @date 2020/4/15 0:27
*/
public class Customer {
public static void main(String[] args) {
//静态代理
BuyHouse buyHouse = new BuyHouseImpl("张三");
BuyHouseStaticProxy buyHouseProxy = new BuyHouseStaticProxy(buyHouse);
buyHouseProxy.buyHouse();
}
}
静态代理总结:
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:
-
需实现相同的接口,如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。
-
代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理.
而且会有过多的代理类。
动态代理
JDK提供了java.lang.reflect.InvocationHandler
接口和 java.lang.reflect.Proxy
类 可以实现
通过一个代理类完成全部的代理功能。(通过反射机制实现动态代理)
Proxy类,它里面有一个很重要的方法 newProxyInstance:
//CLassLoader loader:被代理对象的类加载器
//Class<?> interfaces:被代理类全部的接口
//InvocationHandler h:实现InvocationHandler接口的对象
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
调用Proxy的newProxyInstance方法可以生成代理对象
invocationHandler接口:
//Object proxy:被代理的对象
//Method method:要调用的方法
//Object[] args:方法调用时所需要参数
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
这个方法就是生成的代理类中的方法被调用时会去自动调用的方法,可以看到在这个方法中调用了被代理对象的方法: method.invoke(targetObject, args);
动态代理实现:
public class DynamicProxyHandler implements InvocationHandler {
private Object target;//被代理的对象
public Object newProxyInstance(Object target) {
this.target = target;
//target.getClass().getClassLoader():被代理对象的类加载器
//target.getClass().getInterfaces():被代理对象的实现接口
//this 当前对象,该对象实现了InvocationHandler接口所以有invoke方法,通过invoke方法可以调用被代理对象的方法
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("买房准备");
Object invoke = method.invoke(target, args);
System.out.println("买房装修");
return invoke;
}
}
//动态代理
DynamicProxyHandler proxyHandler = new DynamicProxyHandler();
BuyHouse buyHouse2 = (BuyHouse)proxyHandler.newProxyInstance(buyHouse);
buyHouse2.buyHouse();
动态态代理和静态代理的区别在于静态代理我们需要手动的去实现目标对象的代理类,而动态代理可以在运行期间动态的生成代理类。