Java动态代理深入解析

要想了解Java动态代理,首先要了解什么叫做代理,熟悉设计模式的朋友一定知道在Gof总结的23种设计模式中,有一种叫做代理(Proxy)的对象结构型模式,动态代理中的代理,指的就是这种设计模式。

在我看来所谓的代理模式,和23种设计模式中的“装饰模式”是一个东西。23种设计模式中将它们作为两种模式,网上也有些文章讲这两种模式的异同,从细节来看,确实可以人为地区分这两种模式,但是抽象到一定高度后,我认为这两种模式是完全一样的。因此学会了代理模式,也就同时掌握了装饰模式。

代理模式

代理模式简单来说,就是对一个对象进行包装,包装后生成的对象具有和原对象一样的方法列表,但是每个方法都可以是被包装过的。

静态代理

让我们先来看一段代码:

package common;

public class Test {
    static interface Subject{
        void sayHi();
        void sayHello();
    }
   
    static class SubjectImpl implements Subject{

@Override
        public void sayHi() {
            System.out.println("hi");
        }

@Override
        public void sayHello() {
            System.out.println("hello");
        }
    }
   
    static class SubjectImplProxy implements Subject{
        private Subject target;
       
        public SubjectImplProxy(Subject target) {
            this.target=target;
        }
       
        @Override
        public void sayHi() {
            System.out.print("say:");
            target.sayHi();
        }

@Override
        public void sayHello() {
            System.out.print("say:");
            target.sayHello();
        }
    }
   
    public static void main(String[] args) {
        Subject subject=new SubjectImpl();
        Subject subjectProxy=new SubjectImplProxy(subject);
        subjectProxy.sayHi();
        subjectProxy.sayHello();
    }
}
 

这段代码中首先定义了一个Subject接口,接口中有两个方法。

然后定义了SubjectImpl类实现Subject接口并实现其中的两个方法,到这里肯定是没问题的。

现在再定义一个SubjuectImplProxy类,也实现Subject接口。这个SubjectImplProxy类的作用是包装SubjectImpl类的实例,它的内部定义一个变量target来保存一个SubjectImpl的实例。SubjectImplProxy也实现了接口规定的两个方法,并且在它的实现版本中,都调用了SubjectImpl的实现,但是又添加了自己的处理逻辑。

相信这段代码不难理解,它通过对SubjectImpl进行包装,达到了给输出内容添加前缀的功能。这种代理方式叫做静态代理。

动态代理

从上面的演示中我们不难看出静态代理的缺点:我们对SubjectImpl的两个方法,是进行的相同的包装,但是却要在SubjectImplProxy里把相同的包装逻辑写两次,而且以后如果Subject接口再添加新的方法,SubjectImplProxy也必须要添加新的实现,尽管SubjectImplProxy对所有方法的包装可能都是一样的。

下面我把上面例子的静态代理改成动态代理,我们来看一下区别:

package common;

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

public class Test {
    static interface Subject{
        void sayHi();
        void sayHello();
    }
   
    static class SubjectImpl implements Subject{

@Override
        public void sayHi() {
            System.out.println("hi");
        }

@Override
        public void sayHello() {
            System.out.println("hello");
        }
    }
   
    static class ProxyInvocationHandler implements InvocationHandler{
        private Subject target;
        public ProxyInvocationHandler(Subject target) {
            this.target=target;
        }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/0dab0fb138c3829c8bf6ef3b552a8a73.html