Java动态代理

存在即合理,存在就有存在的理由,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);

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

你可能感兴趣的:(java,动态代理,代理模式,静态代理)