java动态代理

目的:

1.动态代理本身机制的理解

2.动态代理jvm运行的原理。

了解动态代理之前首先要了解代理设计模式。代理模式:当其他对象提供一个代理,用来控制对一个真实对象的访问,代理类用来做一些对委托类消息的预处理,过滤,或者日志处理,这是消息的后续处理等等。主要是为了增加程序的一个灵活性。 

代理模式就是在访问实际对象时,会创建一个代理对象去访问,而不是直接访问实际对象。 在访问实际对象时引入一定程度的间接性,这个间接性可以扩展很多的用途,比如日志,验证等等,还能协调调用者和被调用者的关系,降低系统的耦合度。第二个是代理对象可以作为调用者和实际对象之间的一个中间件,对实际对象起到保护作用。

例子:

现在以一个简单的支付接口为例。

public interface Payment {
    /**
     * @param uid
     * @return
     */
    String doPay(String uid);
}

这是一个支付接口。

public class ThirdChannelPayment implements Payment{

    @Override
    public String doPay(String uid) {
        System.out.println("这是第三方支付! uid :" + uid);
        return "success";
    }
}

这是上面支付接口的实现。

public class ProxyDemo {

    public static void main(String[] args) {
        Payment payment = new ThirdChannelPayment();
        System.out.println(payment.doPay("GZC"));
    }
}

然后对上面的方法进行简单的调用。

输出:

这是第三方支付! uid :GZC
success

现在要在记录支付的日志,我们再创建一个PaymentLogger来做这个事情。然后设计DynamicProxy动态代理类来执行支付之所以要这样设计,是因为如果我们的支付方式有很多的话,要是在支付每个方法都加打印日志的话很繁琐,也不符合设计原则。

public class PaymentLogger {
    public void Log(String uid){
        System.out.println(uid + "发起了支付行为,记录日志!");
    }
}
public class DynamicProxy implements InvocationHandler {
    /**
     * 被代理的对象
     */
    private Object target;

    public Object bind(Object target){
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行前记录日志-----");
        Object result = method.invoke(target,args);
        System.out.println("执行后记录日志=====");
        return result;
    }
}

上面是DynamicProxy代理类。然后将mian方法修改如下:

 public static void main(String[] args) {
        Payment payment = new ThirdChannelPayment();
        DynamicProxy proxy = new DynamicProxy();
        Payment proxyPayment = (Payment)proxy.bind(payment);
        proxyPayment.doPay("GZC");
    }

执行结果:

执行前记录日志-----
这是第三方支付! uid :GZC
执行后记录日志=====

可以看到,在支付方法执行前后我们都可以做自己想做的扩展功能。

小结:虽然我们写的代码量增加了,但是优点是可维护性,灵活性增强了,我们想要代理哪个类,只需要将被代理类传入bind方法就可以了。java jdk的动态代理实现方式有个缺点,代理对象继承了Proxy,所以无法再继承其他类,所以只能通过实现接口的方式完成动态代理,即java jdk提供的代理模式只能代理接口。如果我们要代理一些非接口的实现,就可以使用一些其他的方式,例如Cglib。

下面我们将DynamicProxy使用Cglib来实现:

public class CglibProxy implements MethodInterceptor {


    private Object target;

    public Object getInstance(Object target){
        this.target = target;
        Enhancer enhancer = new Enhancer();//加强器
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行前记录日志-----");
        Object result = methodProxy.invokeSuper(o,objects);
        System.out.println("执行后记录日志=====");
        return result;
    }
}

这是cglib代理类。下面将main方法改写:

    public static void main(String[] args) {
        ThirdChannelPayment payment = new ThirdChannelPayment();
        CglibProxy cglibProxy = new CglibProxy();
        ThirdChannelPayment thirdChannelPaymentProxy = (ThirdChannelPayment) cglibProxy.getInstance(payment);
        thirdChannelPaymentProxy.doPay("GZC");
    }

输出结果:

执行前记录日志-----
这是第三方支付! uid :GZC
执行后记录日志=====

可以看到输出结果与之前相同。需要注意到的是我们使用cglib时,创建代理类传入的是ThirdChannelPayment 这个实体类,而不是之前的Payment 接口。使用cglib,就可以满足我们想要动态代理实体类的需求了。推荐两个其他动态代理工具:javassit,asm。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值