动态代理

动态代理与静态代理相比,其总体实现功能是相同的。

但静态代理中,需要在代理类里实例化实体类,每想增强一个类都需要在代理类中修改,不方便

动态代理使用了诸如反射等方法,可以在不修改代理类的情况下,新增加被代理的类,更方便使用。

java提供了专门实现动态代理的接口InvocationHandler

1. 新建类实现接口

2. 设置bind()方法,主要是用来返回相应增强过的实体类对象(其实是另一个对象Proxy0)

3. 实现invoke()方法,

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {...} 方法,要求三个参数。"参数 proxy 指代理类,method表示被代理的方法,args为 method 中的参数数组,返回值Object为代理实例的方法调用返回的值。这个抽象方法在代理类中动态实现"。

Object argObject = args[0];//拿到实体对象
beforeMethod(argObject);//before方法
Object object = method.invoke(target,args);//原方法
afterMethod();
return object;

搞定代理类之后,可以使用代理类增强原对象的方法

//得到增强的对象

Order2 orderServiceDynamicProxy2 = (Order2) new OrderServiceDynamicProxy(new Order2Impl()).bind();
orderServiceDynamicProxy2.justTest(1);

借鉴一个别人的例子

 

开发一个接口,包含两个方法,可以向指定的人问候“你好”或者“再见”。

public interface IHello {

   void sayHello(String name);

   void sayGoogBye(String name);

}

创建一个简单的类,实现这个IHello接口。

public class Helloimplements implements IHello {
    @Override
    public void sayHello(String name) {
        System.out.println("Hello " + name);
    }
    @Override
    public void sayGoogBye(String name) {
        System.out.println(name+" GoodBye!");
    }
}

消费这个实现类,迄今为止没什么特别的。

现在假设我们接到了这个需求:老板要求在该实现类每次问候某人时,必须把问候的细节记录到日志文件里。为了简单起见,我们在问候前打印下面的一行语句来模拟日志记录的动作。

System.out.println("问候之前的日志记录...");

您也许会说,这还不简单?直接修改Helloimplements的对应方法,把这行日志插入到对应方法即可。

然而,老板的要求是:不允许你修改原来的Helloimplements类。在现实场景中,Helloimplements可能是第三方的jar包提供的,我们没有办法修改代码。

您也许会说,我们可以用设计模式里的代理模式,即创建一个新的Java类作为代理类,同样实现IHello接口,然后将Helloimplements类的实例传入代理类。我们虽然被要求不允许修改Helloimplements的代码,但是可以把日志记录代码写在代理类里。完整代码如下:

public class StaticProxy implements IHello {

  private IHello iHello;

  public void setImpl(IHello impl){

  this.iHello = impl;

}

@Override

public void sayHello(String name) {

    System.out.println("问候之前的日志记录...");

    iHello.sayHello(name);

}

@Override

public void sayGoogBye(String name) {

     System.out.println("问候之前的日志记录...");

     iHello.sayGoogBye(name);

}

static public void main(String[] arg) {

     Helloimplements hello = new Helloimplements();

     StaticProxy proxy = new StaticProxy();

     proxy.setImpl(hello);

     proxy.sayHello("Jerry");

  }

}

这种做法能够实现需求:

下面我们再看如何用InvocationHandler实现同样的效果。

InvocationHandler是一个JDK提供的标准接口。看下面的代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynaProxyHello implements InvocationHandler {
    private Object delegate;
    public Object bind(Object delegate) {
        this.delegate = delegate;
        return Proxy.newProxyInstance(
        this.delegate.getClass().getClassLoader(), this.delegate
        .getClass().getInterfaces(), this);
    }
    public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
        Object result = null;
        try {
            System.out.println("问候之前的日志记录...");
            // JVM通过这条语句执行原来的方法(反射机制)
            result = method.invoke(this.delegate, args);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

上面代码里的bind方法很想我之前代理类StaticProxy的setImpl方法,只不过这个bind方法的输入参数类型更加通用。日志记录的代码写在方法invoke里。

看看如何使用:

static public void main(String[] arg) {
    DynaProxyHello helloproxy = new DynaProxyHello();
    Helloimplements hello = new Helloimplements();
    IHello ihello = (IHello) helloproxy.bind(hello);
    ihello.sayHello("Jerry");
}


作者:JerryWangSAP
链接:https://www.jianshu.com/p/e575bba365f8
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

 

 

 

 

 

 

 

package proxy.staticproxy.dynamicproxy;

import proxy.Order;
import proxy.staticproxy.OrderServiceStaticProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @program: ProxyDesignModen
 * @description: 动态代理
 * @author: Mr.Wang
 * @create: 2019-05-06 15:51
 **/

public class OrderServiceDynamicProxy implements InvocationHandler {
    private Object target;

    public OrderServiceDynamicProxy(Object target) {
        this.target = target;
    }

    //绑定的方法
    public Object bind() {
        Class cls = target.getClass();
        return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),this);

    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object argObject = args[0];
        beforeMethod(argObject);
        Object object = method.invoke(target,args);
        afterMethod();
        return object;
    }

    private void beforeMethod(Object obj){
        int userId = 0;
        System.out.println("动态代理 before core");
        if(obj instanceof Order){
            //如果是order类
            Order order = (Order)obj;
            userId = order.getUserId();
            int dbRouter = userId % 2;
            System.out.println("动态代理分配到【db" + dbRouter + "】处理数据");
        }

    }

    private void afterMethod() {
        System.out.println("动态代理after");
    }
}


 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值