使用代理模式有什么作用?
功能增强
隐藏真实目标
静态代理
例如 :
房东只负责收租,中介负责带租客去看房
厂家负责生产,商铺进行售卖
静态代理是程序执行前就已经设置好的了
缺点 : 需要创建很多代理类和目标类
优点 : 责任分离,可以隐藏真实对象
动态代理
在程序执行之后,使用JDK反射,并动态的指向需要代理的真实目标
可以解决静态代理创建很多代理类的麻烦
JDK动态代理
反射包 java.lang.reflect 里面有三个类
InvocationHandler
创建类,实现这个接口,重写invoke()方法,把原来静态代理中代理类要完成的功能写在里面
Method
执行某个目标类的方法Method.invoke();
Proxy : 创建代理类对象,newProxyInstance();返回值就是地阿里对象
主要方法
InvocationHandler :
public Object invoke(Object proxy, Method method, Object[] args)
// proxy :生成的代理对象;
// method:当前调用的真实方法对象;
// args :当前调用方法的实参;
// 返回:真实方法的返回结果。
Proxy :
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler hanlder)
// loader :类加载器,一般传递真实对象的类加载器;
// interfaces:代理类需要实现的接口;
// handler:代理执行处理器,说人话就是生成代理对象帮你要做什么。
// 返回:创建的代理对象。
cglib动态代理
第三方的工具库,原理是继承,通过继承目标类,子类重写父类中同名的方法,实现功能修改
使用JDK还是cglib?
如果对象实现了接口,默认使用JDK
如果对象没有实现接口,必须采用cglib
JDK代理不需要依赖第三方的库,在JDK环境就可以进行代理
cglib必须依赖于cglib的库
JDK动态代理只能为接口创建代理
cglib可以为普通的类也实现代理
JDK动态代理代码例子
售卖USB功能的接口
/**
* 售卖USB
*/
public interface UsbShell
{
float shell(int amount);
}
USB工厂批发价85元售卖
/**
* 目标类 USB 工厂
*/
public class UsbFactory implements UsbShell
{
/**
* 一个USB卖85块
* @param amount 售卖数量
* @return
*/
@Override
public float shell(int amount) {
System.out.println("目标类");
return 85.0f;
}
}
代理类涨价到100元售卖(功能增强)
/**
* 代理类
*/
public class MyHandler implements InvocationHandler
{
// 传入进来的对象,就是代理类
private Object target;
public MyHandler(Object target)
{
this.target = target;
}
/**
* @param proxy 生成的代理对象
* @param method 当前调用的真实方法对象
* @param args 调用真实方法的参数
* @return 代理类
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
Object res = null;
// 等价于 UsbFactory.shell();
res = method.invoke(target, args);
// 代理类涨价U盘,功能增强
Float price = (Float) res;
price = price + 15;
res = price;
System.out.println("代理类");
return res;
}
}
顾客进行购买
/**
* 购买USB
*/
public class Shop
{
public static void main(String[] args)
{
// 1.创建目标对象
UsbFactory usbFactory = new UsbFactory();
// 2.创建 InvocationHandler 对象
MyHandler myHandler = new MyHandler(usbFactory);
// 3.使用 Proxy 创建代理对象
UsbShell proxy = (UsbShell) Proxy.newProxyInstance(
usbFactory.getClass().getClassLoader(), // loader:类加载器,一般传递真实对象的类加载器
usbFactory.getClass().getInterfaces(), // interfaces:代理类需要实现的接口
myHandler); // handler:代理执行处理器,说人话就是生成代理对象帮你要做什么
// 4.执行方法
float price = proxy.shell(1);
System.out.println("通过动态代理执行方法" + price);
}
}