代理模式
引用:https://www.cnblogs.com/daniels/p/8242592.html
定义:
代理是一种设计模式,是指通过代理对象来访问目标对象,通俗的来讲就像我们生活中的中介、经纪人。
作用:
中介隔离作用:客户类不想或无法直接访问目标类,可使用代理类作为客户类与目标类之间的中介
开闭原则:代理类除了作为客户类与目标类之间的中介,还可以在代理类中增加额外功能来扩展目标类的功能,
一、静态代理:
静态代理指的是,由程序员创建或特定工具自动生成源代码,再对其进行编译。在程序运行前,代理类的.class文件就已经存在了。
代理三要素:接口、接口实现类,接口代理类
接口: public interface BuyHouse { public void buyHouse(); } 实现类: public class BuyHouseImpl implements BuyHouse { public void buyHouse() { System.out.println("买房"); } } 静态代理类: public class StaticProxy implements BuyHouse { private BuyHouse buyHouse; public StaticProxy(final BuyHouse buyHouse) { this.buyHouse = buyHouse; } public void buyHouse() { System.out.println("买房前准备"); buyHouse.buyHouse(); System.out.println("买房后装修"); } } 测试类: public class StaticProxyTest { @Test public void buyHouse(){ BuyHouse buyHouse = new BuyHouseImpl(); StaticProxy buyHouseProxy = new StaticProxy(buyHouse); buyHouseProxy.buyHouse(); } }
结果:
买房前准备
买房
买房后装修
静态代理总结:
优点:在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:需为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
二、JDK动态代理
在动态代理中我们不需要再手动的创建代理类,我们只需要编写一个动态处理器就可以了。真正的代理对象由JDK在运行时动态的来创建。
动态代理类: public class DynamicProxyHandler implements InvocationHandler { private Object object; public DynamicProxyHandler(final Object object) { this.object = object; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("买房前准备"); Object result = method.invoke(object, args); System.out.println("买房后装修"); return result; } } 测试类: public class DynamicProxyHandlerTest { @Test public void buyHouse() { BuyHouse buyHouse = new BuyHouseImpl(); BuyHouse buyHouseProxy = (BuyHouse) Proxy.newProxyInstance(BuyHouse.class.getClassLoader(), new Class[]{BuyHouse.class}, new DynamicProxyHandler(buyHouse)); buyHouseProxy.buyHouse(); } } 结果: 买房前准备 买房 买房后装修
注意Proxy.newProxyInstance()方法接受三个参数:
ClassLoader loader
:指定当前目标对象使用的类加载器Class<?>[] interfaces
:指定目标对象实现的接口的类型,使用泛型方式确认类型InvocationHandler:
指定
动态处理器,
执行目标对象的方法时,会触发事件处理器的方法
jdk动态代理总结:
代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理
三、CGLib动态代理
cglib通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用
动态代理类:
public class CglibProxy implements MethodInterceptor {
private Object target;
public Object getInstance(final Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
//设置为父类
enhancer.setSuperclass(this.target.getClass());
//设置回调函数
enhancer.setCallback(this);
//创建之类
return enhancer.create();
}
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("买房前准备");
//执行目标对象的方法
Object result = method.invoke(target, args);
System.out.println("买房后装修");
return result;
}
}
测试类:
public class CglibProxyTest {
@Test
public void buyHouse() {
BuyHouse buyHouse = new BuyHouseImpl();
CglibProxy cglibProxy = new CglibProxy();
BuyHouse buyHouseProxy = (BuyHouseImpl) cglibProxy.getInstance(buyHouse);
buyHouseProxy.buyHouse();
}
}
结果:
买房前准备
买房
买房后装修
CGLib动态代理总结:
CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。
向上吧,少年