java:动态代理的使用

来源:互联网 发布:.儿童编程小游戏 编辑:程序博客网 时间:2024/05/22 08:45

对于java的使用,真的已经有好几年了。可以说,java的方方面面差不多都有涉猎。但是,也有几个知识点,一直没有怎么涉及。比如:

  • 动态代理
  • 注解
  • GUI

可能是当时学习这些的时候,带给我太多的恐惧,导致我一直不敢再碰这些东西。
不过现在回过头来,再次拾起当时让我恐惧的这些内容,没有当时那么恐惧了;相反,有一种很愉悦的感觉。

顺便说一句:java中应该没有所谓的”静态代理”。因为我看到网上的各种博客/教程/问答,对于静态代理的讲解,其实完全是对装饰者模式的讲解与使用而已。或者是是对聚合模式的使用而已。

闲话不多说,下面我也简单讲解一下我对动态代理的理解与使用。


DynamicProxy

Java 动态代理| jdk & cglib 两种方式实现

所谓动态代理,首先要确立一个目标就是要生成一个目标类的代理对象。

明确了这一目标,后续的实现就有了一个明确的目的性了。

  • 无论是 jdk的原生支持,还是第三方库,比如cglib,目的都是一样的,就是生成一个目标类的代理对象。
  • 拿到代理对象只后,就可以像使用目标对象一样去使用里面的方法。
  • 不过既然是使用代理,就必然希望通过代理,去对目标对象对方法做一些改变,比如增强实现。(加入日志插入等)。这时候,就可以在代理实现等回调方法里面去做一些增强了。

大体上的套路就是这些。至于怎么去使用,往往要看实际应用场景了。

  • jdk对动态代理的支持程度是:被代理方法,必须是接口中的方法。
  • cglib对动态代理对支持程度是:被代理对方法,不能是被final修饰对方法。

好吧:下面分别给出两种实现的简单示例:


  • 基于jdk的实现:

模拟场景:有一个Car类,实现类Moveable接口。然后,通过动态代理去调用Car#move()方法,并在方法执行的前后打印日志。

// interface movaableinterface Moveable {    boolean move(String road);}// class carclass Car implements Moveable {    @Override    public boolean move(String road) {        System.out.println("I am running in road: " + road);        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }        return new Random().nextInt() % 2 == 0;    }}// test mainpublic class TestClient {    public static void main(String[] args) {        Moveable m = new Car();        Class<? extends Moveable> clazz = m.getClass();        Moveable proxyInstance = (Moveable) Proxy.newProxyInstance(clazz.getClassLoader(),                clazz.getInterfaces(),                new InvocationHandler() {                    @Override                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                        System.out.println("do before >>>>");                        long st = System.currentTimeMillis();                        Object invoke = method.invoke(m, args);                        long et = System.currentTimeMillis();                        System.err.println("invoke = " + invoke + " , " + method + " , " + Arrays.toString(args));                        System.out.println("do after <<<<<");                        System.out.println(method.getName() + " 耗时: " + (et - st));                        return invoke;                    }                });        proxyInstance.move("Tokyo");    }}

jdk输出如下:

do before >>>>I am running in road: Tokyoinvoke = false , public abstract boolean com.cat.proxy.dynamic.Moveable.move(java.lang.String) , [Tokyo]do after <<<<<move 耗时: 1001


  • 基于cglib的实现:

模拟场景:有一个Train类,也有一个move方法,通过动态代理,在move方法执行前后,打印日志。
// class train class Train {    public boolean move(String road) {        System.out.println("I am running in road: " + road);        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }        return new Random().nextInt() % 2 == 0;    }}// test mainpublic class TestMain {    public static void main(String[] args) throws InterruptedException {        Train train = new Train();        proxy3(train);    }    private static void proxy3(Train train) {        Enhancer enhancer = new Enhancer();        enhancer.setSuperclass(train.getClass());        enhancer.setCallback((MethodInterceptor) (target, method, objects, methodProxy) -> {            System.out.println("** do before >>> .");//            Object invokeSuper = methodProxy.invokeSuper(target, objects);            Object invokeSuper = method.invoke(train, objects); // 使用 method 和 methodProxy 都可以。            System.err.println((target instanceof Train) + " , " + method + " , " + Arrays.toString(objects) + " , " + methodProxy);            System.out.println("** do after <<<< $ ");            return invokeSuper;        });        Train trainProxy = (Train) enhancer.create();        trainProxy.move("Paris");    } }

cglib输出如下

** do before >>> .I am running in road: Paris** do after <<<< $ true , public boolean com.cat.proxy.dynamic.cglib.Train.move(java.lang.String) , [Paris] , net.sf.cglib.proxy.MethodProxy@78e03bb5

最后,给出完整示例代码。

原创粉丝点击