zoukankan      html  css  js  c++  java
  • Java程序中的代理作用和应用场景及实现

    The role of proxy, application scenarios, and implementation in Java programs.

    代理是程序设计和开发时频繁使用的技术,可以提高程序灵活性和可扩展性。

    1 代理作用

    1. 在不修改原代码的基础上,扩展和增强实现;
    2. 代码解耦,在代理中通过参数可以判断真实类,做出不同的响应或调用,灵活方便;
    3. 隐藏部分实现过程和细节。

    2 应用场景

    java_proxy

    ICar接口类,有一个drive方法,传入speed(速度)行驶,现在已经有Mitsubishi(三菱车)和Bwm(宝马车)实现了接口,随着业务发展,可能有更多的车加入;程序稳健运行一段时间后,针对不同的车发现了不同的问题需要处理,比如Mitsubishi车drive前必须检查和保证冷却液充足;Bwm车drive前必须检查和保证机油充足;由于改写ICar接口可能影响到其它的车;如果有很多的车要处理,更改实现类可能需要花费大量时间,此时可以通过代理类扩展和增强。

    java_proxy

    在代理类(CarProxy)中通过carCheck方法实现对不同汽车检查,检查通过后drive汽车,从而实现对原有代码增强。

    3 代理的实现

    3.1 静态代理

    静态代理的思想:代理类和其它汽车类一样实现接口类,在重写方法里实现扩展或增强,并调要汽车类实现。

    //宝马汽车实现类
    class Bwm implements ICar {
        public void drive(int speed) {
            System.out.println("Bwm drive with speed:"+speed);
        }
    //三菱汽车实现类   
    class Mitsubishi implements ICar {
        public void drive(int speed) {
            System.out.println("Mitsubishi drive with speed:"+speed);
        }
    
    //汽车代理类
    public class CarProxy implements ICar {
        private ICar carTarget;
        public CarProxy(ICar carTarget){
            this.carTarget=carTarget;
        }
        // 车辆检查
        private boolean carCheck() {
            if(this.carTarget instanceof Mitsubishi){ //判断汽车类型
                System.out.println("Mitsubishi 检查冷却液完成。");
                return true;
            }else if(this.carTarget instanceof Bwm){
                System.out.println("Bwm 检查机油完成。");
                return true;
            }else{
                System.out.println("该车不需要检查。");
                return true;
            }
        }
    
        /** 驾驶
         * @param speed 速度
         */
        public void drive(int speed) {
            if(carCheck()){ //检查通过后drive
                carTarget.drive(speed); //调用汽车类
            }
        }
    }
    

    在CarProxy代理类中,增加了对不同汽车的检查方法(carCheck),当汽车检查通过后调用(drive)方法驾驶汽车。这样代理类便实现了对三菱和宝马车的扩展,调用时传入ICar实现类对象;

    new CarProxy(new Mitsubishi()).drive(80); //drive 三菱车
    new CarProxy(new Bwm()).drive(100); //drive 宝马车
    

    运行输出;

    Mitsubishi 检查冷却液完成。
    Mitsubishi drive with speed:80
    Bwm 检查机油完成。
    Bwm drive with speed:100
    

    3.1.1 缺点

    接口类变化会影响实现类和代理类;比如方法修改返回值、参数类型、增加方法,实现类和代理类都需要修改。

    3.2 动态代理

    Java 提供(java.lang.reflect.InvocationHandler)代理实例接口,代理类实现该接口关联调用处理程序的方法(invoke),当在代理实例调用方法时,方法调用被编码(encoded)并分配给其调用处理程序的方法。

    public class DynamicProxy implements InvocationHandler{
        Object carTarget;
    
       //车辆检查
       private boolean carCheck() {
           if(this.carTarget instanceof Mitsubishi){
                System.out.println("Mitsubishi 检查冷却液完成。");
                return true;
           }else if(this.carTarget instanceof Bwm){
                System.out.println("Bwm 检查机油完成。");
                return true;
           }else{
               System.out.println("该车不需要检查。");
               return true;
           }
       }
    
        //创建代理类实例
        Object crateProxyInstance(Object carTarget) {
                this.carTarget = carTarget;
                return Proxy.newProxyInstance(carTarget.getClass().getClassLoader(), 
                carTarget.getClass().getInterfaces(),this);
            }
    
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                if(carCheck()){//汽车检查通过后drive
                    return method.invoke(carTarget,args);
                }
                return null;
            }
    }
    

    除了crateProxyInstance 和 invoke 方法外,对三菱和宝马车的扩展(车辆检查)与静态类相同。调用时同样传入ICar实现类对象。

    ((ICar)new DynamicProxy().crateProxyInstance(new Mitsubishi())).drive(80);//drive 三菱车
    ((ICar)new DynamicProxy().crateProxyInstance(new Bwm())).drive(80);//drive 宝马车
    

    3.3 cglib 代理

    除了java自身的代理类,还有第三方代理类,比如(cglib),通过实现方法拦截器(MethodInterceptor),在拦截方法中(intercept)调用处理程序的方法。

    import java.lang.reflect.Method;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    public class CarInterceptor implements MethodInterceptor{
        Object carTarget;
    
       //车辆检查
       private boolean carCheck() {
           if(this.carTarget instanceof Mitsubishi){
                System.out.println("Mitsubishi 检查冷却液完成。");
                return true;
           }else if(this.carTarget instanceof Bwm){
                System.out.println("Bwm 检查机油完成。");
                return true;
           }else{
               System.out.println("该车不需要检查。");
               return true;
           }
       }
        //拦截方法 
        @Override
        public Object intercept(Object carTarget, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            this.carTarget=carTarget;
            if(carCheck()){//汽车检查通过后drive
                Object obj=proxy.invokeSuper(carTarget, args);
                return obj;
            }
            return null;
        }
    }
    

    最后调用时,首先实例化(Enhancer)对象启用方法拦截器,设置方法拦截类和Superclass;

    Enhancer en=new Enhancer(); 
    en.setCallback(new CarInterceptor());//设置拦截类
    //drive 三菱车
    en.setSuperclass(new Mitsubishi().getClass());//设置superClass
    ((ICar) en.create()).drive(80);
    //drive 宝马车
    en.setSuperclass(new Bwm().getClass());
    ((ICar) en.create()).drive(100);
    

    4 总结

    静态代理更像是开发层面的实现,每次修改接口类或实现类都可能需要修改代理类,随着程序扩展,代码量和维护量增加;Java 提供的(java.lang.reflect.InvocationHandler)代理实例接口和第三方代理类(cglib)大大弥补了静态类的不足,也应用在许多开源框架上,比如Spring。

    参考文献

    Hope is personal,hope is something that no one can give to you,you have to choose to believe in hope,you have to make it yourself..
  • 相关阅读:
    移动端开发
    webpack2系列step2--CSS
    webpack2系列step1--HTML
    react+redux官方实例TODO从最简单的入门(6)-- 完结
    react+redux官方实例TODO从最简单的入门(5)-- 查
    react+redux官方实例TODO从最简单的入门(4)-- 改
    react+redux官方实例TODO从最简单的入门(3)-- 删
    react+redux官方实例TODO从最简单的入门(1)-- 前言
    react+redux官方实例TODO从最简单的入门(2)-- 增
    Git 标签管理
  • 原文地址:https://www.cnblogs.com/lanston/p/14613100.html
Copyright © 2011-2022 走看看