java动态代理对代理模式的实现

代理模式是什么:
当两个类 类a与类b发生交互时,不让类b直接与类a接触,而是通过代理类c与类a交互,类c内部调用类a的处理方法,但在调用前后可以根据需求做不同的处理,使用代理类类c实现了对类a的消息过滤,转发,后续处理等操作,保护并隐藏了类a,为设计不同的策略留下控件,使程序设计更加灵活。


什么情况下需要实现代理:在调用核心方法前进行参数检查;在目标方法前后添加事务;添加缓存
举例来说,定义公用接口vehicle;
public  interface  Vehicle {
      void run();
}

标识车辆的抽象,都有一个run方法;实现这个接口的有各种各样的车 比如:
public  class  Bus  implements  Vehicle{
      @Override
      public  void  run() {
            // TODO Auto-generated method stub
           System. out .println( "bus is running" );
     }
}
或者:

public  class  Cars  implements  Vehicle{
      @Override
      public void  run() {
            // TODO Auto-generated method stub
           System. out .println( "car is running" );
           
     }
     
}
....
这些实现vehicle接口的类称为委托类;

现在有一个需求,就是给这些所有的车run之前执行人上车动作,run执行之后执行车上的人下车动作;在保证面向对象原则下解决方案大致有:

1。 直接修改实现类或者给每个委托类创建子类重写run方法 : 可以想象,如果委托类有100多个,将是一个相当繁杂的工作,而且继承实现的多层父子关系使代码臃肿,不利于后期维护。
2.    使用代理类ProxyVehicle:
public  class  ProxyVehicle  implements  Vehicle {
     Vehicle  v ;
      public  ProxyVehicle(Vehicle v) {
            // TODO Auto-generated constructor stub
            this . v = v;//在实际使用中,只需根据需要将不同的委托类传入代理类构造方法中,就完成了该委托类上下车功能的升级;
     }
      @Override
      public  void  run() {
           System. out .println( "快上车!" );//上车动作
            v .run();
           System. out .println( "下车啦!" );//下车动作
     }
}

在实际使用中,只需根据需要将不同的委托类传入代理类构造方法中,就完成了该委托类上下车功能的升级;

public  class  Client {
      public  static  void  main(String[] args) {
           
          
           Vehicle vehicle = new Bus();
           
           Vehicle proxyVehicle= new  ProxyVehicle(vehicle);
           
           proxyVehicle.run();
     }
}

长远来看,如果以后不仅添加上下车功能,如果还要添加日志打印功能,权限检查功能,异常处理功能,难道要每个需求都分别给每个实现类重新创建一个代理类或者挨个修改?显然使用代理模式更加方便。 由此可见,使用代理模式相对于方法一有着不小的优势。

上面方法二就是静态代理,为了保持行为的一致性,静态代理类ProxyVehicle也要实现Vehicle接口,这就使静态代理有了很大的局限性,即 一个代理类只能为一个接口服务,在这个例子中这个被服务的接口是Vehicle,其他的类,比如有AircraftCarrier,Battleships等委托类实现了Ships接口,在Ships接口中有Sali()方法,那么如果要给Sail()前后添加上人,下人功能,就要重新定义一个代理类,来实现Ships接口.



为了弥补静态代理这个缺点,出现了动态代理
这里以jdk动态代理为例 还是那个Vehicle的例子;
实现动态创建代理类,只需一行代码:
 DynamicProxyInvocator ih= new  DynamicProxyInvocator(vehicle);
       
Vehicle proxyVehicle = (Vehicle) Proxy.newProxyInstance(
                     Bus. class .getClassLoader()           //第一个参数,指定类加载器,一般用委托类的加载器
                   , new Class<?>[] { Vehicle. class }     //第二个参数,指定创建的代理类将为这个类实现的哪       ~                                                         //些接口服务
                   , ih                                    //第三个参数,指定要对这些接口做什么样的处理和服~                                                         //务
);


唯一在之前静态代理没有出现的是第三个参数,ih是实现InvocationHandler接口的实例,自定义 DynamicProxyInvocator
import  java.lang.reflect.InvocationHandler;
import  java.lang.reflect.Method;
public  class  DynamicProxyInvocator  implements  InvocationHandler {
     Object  v ;//与静态代理不同,这里被代理类型不再指定为Vehicle
      public  DynamicProxyInvocator(Object obj) {
            v = obj;
     }
      @Override
      public  Object invoke(Object proxy, Method method, Object[] args)
                 throws Throwable {
           System. out .println( "上车!" );
           method.invoke( v , args);  //反射调用相应函数  
           System. out .println( "下车!" );
            return  null ;
     }
}
可以看到,在使用动态代理时没有写死代理类是对哪个类做的代理,InvocationHandler中也未指定该代理类是专门为某个接口服务的;

继续上面Vehicle与Ships的例子,要想简单地为所有的Ship也添加上人 下人功能,只需做如下修改


           Ships acc= new  AirCraftCarrier();
           DynamicProxyInvocator ih = new  DynamicProxyInvocator(acc); //上下人功能
           
           Ships proxyShip = (Ships) Proxy.newProxyInstance(Ships. class .getClassLoader(),
                      new Class[] { Ships. class }, ih);
           proxyShip.sail();


即可为所有实现Ships接口的船添加上下人的功能。

值得一提的是,newProxyInstance的第二个参数是一个数组,可以传入想扩展的所有被代理类实现的接口,只有在这里指定了该接口,InvocationHandler才会拦截该方法,并添加InvocationHandler中做的修饰。另外,在InvocationHandler的
    public  Object invoke(Object proxy, Method method, Object[] args)
方法中,可以用method.getName()得到当前拦截到的方法名,进行分别处理。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值