JDK动态代理模式小白式详解

动态代理模式到底是干啥的?

答:当我们想去修改一个类的实现,而又不能去直接修改、干预该类的代码时,我们就需要一个该类的代理类来辅助我们。

比如,我们想在每次调用某个类的save方法时,都在日志文件里写下日志信息,这时候,在不影响原来的代码的封装的前提下,我们可以手动的去创建一个该类的代理类,来代替该类帮我们实现一些附加的方法。直接看代码:

定义接口PersonDAO:

package top.xiaohang456.spring.staticProxy;

public interface PersonDAO {
    void save();
}

定义接口的实现类PersonDAOImpl

package top.xiaohang456.spring.staticProxy;

public class PersonDAOImpl implements PersonDAO {

    @Override
    public void save() {
        System.out.println("Person save success!");
    }
}

OK,现在我们假设上边的类已经封装好了,而我们也不能再去直接修改它的代码了,但我们想在每次调用PersonImpl的save方法时都加上一个事务,让每次被调用之前都在日志里写下“Transaction Begin”,在每次调用过后也在日志里写一个东西,怎么办呢?我们可以定义如下一个Transaction类,专门来存储我们下要让其附加的事务:

package top.xiaohang456.spring.staticProxy;

public class Transaction {
    public void beginTransaction(){
        System.out.println("Transaction Begin!");
    }

    public void commit(){
        System.out.println("Transaction commit!");
    }
}

然后我们怎么办呢?这时,我们就要用到java反射机制了,首先我们要了解的一个接口就是InvocationHandler接口,这是我们定义拦截器(或者说事务调用处理器,但这可不是一个代理类,稍后我们会说这其中的区别)所必须实现的一个接口,这个接口,只定义了一个方法--invoke方法,稍后我们会说明这个方法的具体作用。先看代码:

package top.xiaohang456.spring.JDKProxy;

import top.xiaohang456.spring.staticProxy.Transaction;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class Interceptor implements InvocationHandler {
    private Object target;
    private Transaction transaction;

    public Interceptor(Object target, Transaction transaction){
        this.target = target;
        this.transaction = transaction;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        this.transaction.beginTransaction();
        method.invoke(target);
        this.transaction.commit();
        return null;
    }
}

想必看完之后你一定有很多疑惑,下边就听小菜为您一一解答。

首先,不难看出我们在这个类里定义了两个私有变量,而且我们还定义了它的含参的构造方法来初始化这两个成员变量,那么Transaction被实例化出来我们还可以理解,因为我们要调用其中的方法来帮我们完成一些辅助事务,可这个Object又为何产生呢?这个名为target的Object,就是我们的代理对象,那你可能会问:为啥我不直接定义一个PersonDAO呢?而去定义一个Object呢?这,就体现了动态代理的好处之一,不光光是PersonDAO可以使用我们所定义的拦截器,其他的类也可以用!因为Object是所有类的祖宗类吖!这个暂时不理解也没关系,我接着说您就明白了。

好,我们现在直接测试这个拦截器,先不管这个invoke方法(TrustMe!)

package top.xiaohang456.spring.JDKProxy;

import org.junit.Test;
import top.xiaohang456.spring.staticProxy.PersonDAO;
import top.xiaohang456.spring.staticProxy.PersonDAOImpl;
import top.xiaohang456.spring.staticProxy.Transaction;

import java.lang.reflect.Proxy;

public class TestJDKProxy {

    @Test
    public void test(){
        Object target = new PersonDAOImpl();
        Transaction transaction = new Transaction();
        Interceptor interceptor = new Interceptor(target, transaction);

        PersonDAO personDAO1 = (PersonDAO) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),interceptor);
        personDAO1.save();

    }
}

如上就是我们所定义的测试类,我们先实例化出了我们的被代理类,和我们的事务类,在用着两个类作为参数去实例化我们的Interceptor,然后。。。

Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),interceptor);

这个又是什么鬼?

这个就是我们的重头戏和切入点!

Proxy是java.lang.reflect包下的一个类,Proxy本身就是代理的意思,那它的这个newProxyInstance()方法顾名思义就是根据传入的参数来实例化出一个代理类出来,API中这个方法的定义是这样的:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)

参数:

loader - 定义代理类的类加载器

interfaces - 代理类要实现的接口列表

h - 指派方法调用的调用处理程序

上述的三个参数就是我们想要生成一个代理类所需要的三个要素,第一个为ClassLoader(类加载器),第二个为被代理类所实现的接口(我想生成你的代理类,你当然要把你所实现的接口都给我一份啦!我才去实现这些接口,并且知道你都定义了哪些方法),第三个,就是我们所定义的那个Interceptor,拦截器!

有了这三个参数,我们就能生成一个名为personDAO1的代理类了!Then,我们用这个代理类去调用save方法的时候又发生了什么呢?答案是:我们的这个代理类,会把它自己(一个Object对象)、这个被调用的方法名(此处为save)、以及所传入该方法的参数(此处没定义...save方法没定义参数),统统都,传给Interceptor的invoke方法!这就是invoke方法那三个参数的由来!现在再看回去,一切都豁然开朗了~~~

在此代理模式中,不仅代理是动态产生的(即在运行的时候生成),而且还在代理的时候,也增加了一些处理。在此处增加的处理,其实就是另一种编程思想-----面向切面编程思想(AOP Aspect Oriented Programming)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

请保持优秀。

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

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

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

打赏作者

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

抵扣说明:

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

余额充值