Java代理模式详解

一、什么是代理模式

代理模式为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用, 其特征是代理类与委托类有同样的接口。代理模式是常用的java设计模式。

代理模式能够在不修改源码的情况下增强方法,在方法前后增加日志记录,权限管理等功能。

表现形式如图:

img

 

在Java中,代理模式分成2种:静态代理模式和动态代理模式;

  1. 静态代理的模式在平时生活中也很常见,比如买火车票这件小事,黄牛相当于是火车站的代理,我们可以通过黄牛或者代售点进行买票行为,但只能去火车站进行改签和退票,因为只有火车站才有改签和退票的方法。

  2. 动态代理中,代理类并不是在Java代码中实现,而是在运行时期生成,相比静态代理,动态代理可以很方便的对委托类的方法进行统一处理,如添加方法调用次数、添加日志功能等等,动态代理分为jdk动态代理和cglib动态代理,下面通过一个例子看看如何实现jdk动态代理。

二、代理模式的优缺点

  1. 优点:

    • 职责清晰。

    • 高扩展性。

    • 智能化。

  2. 缺点:

    • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。

    • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

  3. 其他模式对比

    • 和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。

    • 和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

三、使用场景

代理模式主要解决在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

1.应用场景

按职责来划分,通常有以下使用场景:

  1. 远程代理。

  2. 虚拟代理。

  3. Copy-on-Write 代理。

  4. 保护(Protect or Access)代理。

  5. Cache 代理。

  6. 防火墙(Firewall)代理。

  7. 同步化(Synchronization)代理。

  8. 智能引用(Smart Reference)代理。

2.应用实例

  1. Windows 桌面以及资源管理器里面的快捷方式。

  2. 买火车票不一定在火车站买,也可以去代售点,也可以网购。

  3. Spring AOP 中 用到的动态代理。

四、代码实现

1. 静态代理模式

静态代理满足如下的几个条件:

  1. 代理对象的类是真实存在的,并非动态生成的。

  2. 代理对象持有被代理对象的引用。

  3. 代理对象中的方法通过被代理对象的引用调用被代理对象的方法,同时执行代理逻辑。

     

下面是一个简单的代理模式:

接口类:

 

/* * 接口 * 代理类和委托类都必须实现该类 */public interface ISubject {
//处理任务的抽象方法public void dealTask(String task);}

委托类:

 

/* * 真实角色(被代理类,委托类) * 实现接口Isubject */public class RealSubject implements ISubject {@Overridepublic void dealTask(String task) {//真实角色处理任务System.out.println("正在"+task);}
}

代理类:

 

/* * 代理类 * 实现ISubject接口 *  持有被代理类的引用 */public class Proxy implements ISubject {
//持有被代理类的引用private RealSubject realSubject;
//在构造方法中初始化被代理类public Proxy(RealSubject r) {this.realSubject=r;}
@Override//在该方法中加入代理逻辑public void dealTask(String task) {System.out.println("开始帮忙....");//加入线程睡眠模拟帮忙的行为try {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//真正执行动作的仍然是真实角色realSubject.dealTask(task);}
}

静态工厂类:

 

/* * 静态工厂类 * 对于客户端来说 并不关心执行动作的是代理对象还是真实角色 * 所以我们创建一个静态方法直接返回对象 */public class StaticFactory {
//调用此方法获得实例public static ISubject getInstance(){return new Proxy(new RealSubject());}}

测试类:

 

/* * 测试类(客户类) */public class Test {
public static void main(String[] args) {//创建代理对象时需要一个真实对象的实例ISubject instance = StaticFactory.getInstance();//使用代理类的方法instance.dealTask("敲代码");}}

真正的业务功能还是有委托类来实现,但是在实现业务类之前的一些公共服务。例如在项目开发中我们没有加入缓冲,日志这些功能,后期想加入,我们就可以使用代理来实现,而没有必要打开已经封装好的委托类。

2.动态代理模式

1、定义业务逻辑

 

public interface Service {        //目标方法       public abstract void add();  }
public class UserServiceImpl implements Service {        public void add() {              System.out.println("This is add service");       } }

2、利用 java.lang.reflect.Proxy类和 java.lang.reflect.InvocationHandler接口定义代理类的实现。

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
class MyInvocatioHandler implements InvocationHandler {      private Object target;      public MyInvocatioHandler(Object target) {            this.target = target;       }        @Override       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("-----before-----");             Object result = method.invoke(target, args);             System.out.println("-----end-----");             return result;       }        // 生成代理对象       public Object getProxy() {             ClassLoader loader = Thread.currentThread().getContextClassLoader();            Class<?>[] interfaces = target.getClass().getInterfaces();             return Proxy.newProxyInstance(loader, interfaces, this);       } }

3、使用动态代理

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
 public class ProxyTest {          public static void main(String[] args) {               Service service = new UserServiceImpl();               MyInvocatioHandler handler = new MyInvocatioHandler(service);               Service serviceProxy = (Service)handler.getProxy();               serviceProxy.add();        }   }

执行结果:

  •  
  •  
  •  
   -----before-----       This is add service     -----end-----

更多内容请关注公众号《码上同行》:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

new^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值