Java动态代理

来源:互联网 发布:软件文件夹命名规则 编辑:程序博客网 时间:2024/04/29 21:33

存在即合理,存在就有存在的理由,java动态代理的存在是为了解决静态代理出现的不足,所以首先看一看什么是静态代理:
有如下接口:

public interface SayHello {    void sayHello();}

有如下实现:

public class HelloImpl1 implements SayHello {    public void sayHello() {        System.out.println("你好");    }}
public class HelloImpl2 implements SayHello {    public void sayHello() {        System.out.println("Hello");    }}

此时我们如果有一种需求,就是在每一种实现了SayHello接口的sayHello方法前面或后面都加一个固定的操作,比如说每次sayHello前握手,那么我们要去修改每一个实现类吗?如果不使用代理模式,这是必须的,所以出现了静态代理

我们需要通过代理类取访问具体的实现对象,所以代理类也需要实现具体的接口,这样做是方便我们知道我们在每个方法前后都做了什么,我想,其实代理类不实现SayHello接口也可以使用,但是这样的类多了以后,会很混乱,不知道某个代理类具体是代理什么的,实现接口后,很明显就知道是为了代理某个接口的实现类

public class HelloProxy implements SayHello{    //通过代理取访问这个target目标对象    SayHello target;    public HelloProxy(SayHello target) {        this.target = target;    }    public void sayHello() {        //先握手        System.out.println("握手");        target.sayHello();    }}

这样代理之后,我们就不用一个个去修改实现类了,只需要将以前调用SayHello实现类的地方改为调用这个HelloProxy代理对象的sayHello()就可以了。如果最开始就使用代理模式,那么为了加“握手”操作就只需要修改代理类,其他地方完全不用修改。

以上就是静态代理,为什么说是静态呢?
试想,如果我们修改了接口呢?如果接口新添加了一个方法,我们是不是要在代理类中也实现这个方法,并且再将“握手”操作添加进去(这样比喻似乎不是很合理,毕竟不是每一种方法前面都需要握手。可以把“握手”换成“安全检查”,有一种情况,是我们在调用这个类的方法前都需要进行安全检查,那这种说法就是合理的)。
所以,动态代理就是这样的:当接口改变时,我们不需要改变代理类,不需要手动的在每个新方法前面都加上“握手”操作。

动态代理如何实现呢?Java给我们提供了简单方法,分两步:
(1)说明我们想要在每个方法前后加上什么操作(不限定接口)
(2)JVM运行时动态的生成代理类(限定接口,只能生成代理某个接口的代理类,在这种接口每个方法前后都加上第(1)步中规定的操作)

我们来实现SayHello接口的代理,在方法前面加上“握手”操作,按照上面的步骤来进行:
(1)说明我们想要在每个方法前后加上什么操作

//我们需要实现InvocationHandler接口,告诉我们需要添加“握手”操作public class Operation implements InvocationHandler {    //代理的对象是这个    Object originObj;    public Operation(Object originObj) {        this.originObj = originObj;    }    //这里使用反射来实现调用类内部的方法,所以参数有:类实例,方法,给方法的参数。    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("握手");        return method.invoke(originObj, args);    }}

这里没有指定接口,所以任意一个类都可以使用这个代理,来实现在前面加上“握手”操作。

(2)JVM运行时动态的生成代理类
我们来生成一个SayHello接口的代理类

SayHelloImp hello = new SayHelloImp();//生成一个操作对象,告诉JVM要添加什么操作Operation operation = new Operation(hello);//后面的3个参数,后两个告诉Proxy要代理什么接口,添加什么操作。第一个暂时不清楚。SayHello helloProxy = (SayHello) Proxy.newProxyInstance(hello.getClass().getClassLoader(),hello.getClass().getInterfaces(),operation);

好了,这就是动态代理的概念以及使用,想知道最终生成的代理实例代码是什么样子,请移步我的另一片博文

0 0
原创粉丝点击