设计模式 四、代理模式

代理模式,为其他对象提供一种代理以控制对这个对象的访问。

静态代理
委托者和代理者实现同一个接口,委托者持有代理者的实例,在代理任务的过程中可以做些其他事情,比如
远程代理:为一个对象在不同的地址空间提供局部代表,隐藏一个对象存在不同地址空间的事实。

虚拟代理,根据需要创建开销很大的对象, 通过它来存放实例化需要很长时间的真实对象。如打开网页时未加载的图片,此时代理存储了真实图片的路径和尺寸。

安全代理,用来控制真实对象访问的权限。

智能指引,代理处理另外一些事。如计算真实对象的引用次数,无引用时释放对象。访问对象前,检查是否已经锁定它,这样其他对象无法改变它。第一次引用一个持久对象时,把它装入内存等等。

静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类.

//接口
public interface I {
    
    
    void operation();
}

//委托类
public class Subject implements I{
    
    
    @Override
    public void operation() {
    
    
        System.out.println("我是委托者");
    }
}

//代理类
public class ProxyMan implements I {
    
    
    I i;

    public ProxyMan(I i) {
    
    
        this.i = i;
    }

    @Override
    public void operation() {
    
    
        System.out.println("我是代理者,执行了代理");
        i.operation();
    }

    public static void main(String[] args) {
    
    
        gdut.iot.softdev.review.pattern.proxy.simple.Subject subject = new Subject();
        ProxyMan proxyMan = new ProxyMan(subject);
        proxyMan.operation();
    }
}

动态代理

1.JDK特性的代理
代理类并非在Java代码中定义,而是运行期根据一些指示生成的

  • 可以很方便的对代理类的函数进行统一管理,不需要逐个方法修改
  • 代理关系没有硬编码,可以在运行时动态改变
  • 解决方法:对发送给服务对象的请求进行拦截,加入处理逻辑后决定是否放行
  • 动态代理类涉及的角色
  • 委托类(服务对象)和代理类的公共接口
  • 具体实现该接口的服务对象
  • InvocationHandler接口,会被Proxy类回调,需要一个实现了InvocationHandler的类,在invoke方法中添加代理的逻辑
  • 动态代理的核心类Proxy
//接口
public interface Subject {
    
    
    void goshopping();
}

//委托类
public class RealSubject implements Subject{
    
    
    public RealSubject() {
    
    
    }

    @Override
    public void goshopping() {
    
    
        System.out.print("Realgoshopping");
    }
}

//代理类

*基于JDK的动态代理有两个类要记住,Proxy和InvocationHandler( 接口)蔡渣男想找个代理对象代替他白嫖,首先要把自己这个对象托付给一个类,这个类要实现InvocationHandler接口。

这个类实现了这个接口,重写invoke方法对蔡渣男的白嫖方法进行扩展
public class ProxyMan implements InvocationHandler {
    
    
    Subject target;

    public ProxyMan(Subject target) {
    
    
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        System.out.print("开始代理");
        Object result = method.invoke(target, args);//invoke方法是利用反射调用实际的方法
        return result;
    }

    public static void main(String[] args) {
    
    
        Subject realSubject = new RealSubject();
        InvocationHandler proxyMan = new ProxyMan(realSubject);
        Subject realSubjectProxy = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),
                new Class<?>[]{
    
    Subject.class}, proxyMan);
        realSubjectProxy.goshopping();//参数分别是 代理类的加载器 被代理的接口 代理类实例 原理是通过反射调用这个方法

    }
}
  1. CgLib 动态代理:继承

被代理类没有实现接口的情况下应该用CGLIB, CGLIB是一种通过继承的方法对对象进行代理,构建被代理对象的子类,子类中继承了父类的所有方法,可以通过在子类中重载父类方法来进行功能增强。

需要导入Cgilb的包

import gdut.iot.softdev.rtti.proxy.cglibproxy.CglibMethodInterceptor;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodProxy;
//父类,委托类 想要对这个类增强,可以构建一个子类来实现
public class Dog {
    
    
    public void call() {
    
    
        System.out.print("www");
    }
}

//拦截类要实现MethodInterceptor接口,在intercept方法中扩展代理对象,注意jdk是对象操作,而cglib是类操作
public class CgLibInterceptor extends CglibMethodInterceptor {
    
    

    @Override
    public Object CglibProxyGeneratory(Class target) {
    
    
        //这里有用到一个类叫Enhancer,通过这个类可以设置委托类为父类,此类为子类
        Enhancer enhancer = new Enhancer();
        //把被代理类设置为父类
        enhancer.setSuperclass(target);
        enhancer.setCallback(this);
        //生成一个继承target类的代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    
    
        System.out.print("k开始代理");
        //对这个类来说,执行原本的方法就是执行他父类的方法,所以用invokeSuper 是方法的调用 不是进行反射 
        Object result = proxy.invokeSuper(obj,args);
        return result;
    }

    public static void main(String[] args) {
    
    
        CgLibInterceptor cgLibInterceptor = new CgLibInterceptor();
        //传入被代理类。
        Dog dogProxy = (Dog) cgLibInterceptor.CglibProxyGeneratory(Dog.class);
        dogProxy.call();
    }

1、JDK动态代理具体实现原理:

通过实现InvocationHandler接口创建自己的调用处理器;

通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理;

通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型;

通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入;

2、CGLib动态代理:

利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

3、两者对比:

JDK动态代理是面向接口的。

CGLib动态代理是通过字节码底层继承要代理类来实现,因此如果被代理类被final关键字所修饰,会失败

猜你喜欢

转载自blog.csdn.net/weixin_45401129/article/details/114629178