Java 静态代理、动态代理的使用

原文:Java 动态代理。简单修改。

静态代理

创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。

接口:

public interface HelloInterface {
    void sayHello();
}

被代理类:

public class Hello implements HelloInterface{
    @Override
    public void sayHello() {
        System.out.println("Hello zhanghao!");
    }
}

代理类:

public class HelloProxy implements HelloInterface{
    private HelloInterface helloInterface = null;
    public HelloInterface(HelloInterface o) {
        helloInterface = o;
    }
    @Override
    public void sayHello() {
        System.out.println("Before invoke sayHello" );
        helloInterface.sayHello();
        System.out.println("After invoke sayHello");
    }
}

代理类调用:

被代理类被传递给了代理类 HelloProxy,代理类在执行具体方法时通过所持用的被代理类完成调用。

public static void main(String[] args) {
    HelloProxy helloProxy = new HelloProxy(new Hello());
    helloProxy.sayHello();
}
Before invoke sayHello
Hello zhanghao!
After invoke sayHello

使用静态代理很容易就完成了对一个类的代理操作。但是静态代理的缺点也暴露了出来:由于代理只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐。

动态代理

利用反射机制在运行时创建代理类。

接口、被代理类不变,我们构建一个 handler 类来实现 InvocationHandler 接口。

public class ProxyHandler implements InvocationHandler{
    private Object object;
    public ProxyHandler(Object object){
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before invoke "  + method.getName());
        method.invoke(object, args);
        System.out.println("After invoke " + method.getName());
        return null;
    }
}

使用动态代理:

public static void main(String[] args) {
    HelloInterface hello = new Hello();

    InvocationHandler handler = new ProxyHandler(hello);

    HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(
        hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);

    proxyHello.sayHello();
}
Before invoke sayHello
Hello zhanghao!
After invoke sayHello

通过 Proxy 类的静态方法 newProxyInstance 返回一个接口的代理实例。针对不同的代理类,传入相应的代理程序控制器 InvocationHandler。

如果新来一个被代理类 Bye,如:

public interface ByeInterface {
    void sayBye();
}
public class Bye implements ByeInterface {
    @Override
    public void sayBye() {
        System.out.println("Bye zhanghao!");
    }
}

那么执行过程:

public static void main(String[] args) {
    HelloInterface hello = new Hello();
    ByeInterface bye = new Bye();

    InvocationHandler handler = new ProxyHandler(hello);
    InvocationHandler handler1 = new ProxyHandler(bye);

    HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(
        hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);

    ByeInterface proxyBye = (ByeInterface) Proxy.newProxyInstance(
        bye.getClass().getClassLoader(), bye.getClass().getInterfaces(), handler1);
    
    proxyHello.sayHello();
    proxyBye.sayBye();
}
Before invoke sayHello
Hello zhanghao!
After invoke sayHello
Before invoke sayBye
Bye zhanghao!
After invoke sayBye

对于 Hello 和 Bye,能够使用同一个代理处理器 ProxyHandler 实现代理,是因为不会直接告诉 ProxyHandler 所代理的类实现了哪些接口,也就是说 ProxyHandler 不依赖于指定接口,这意味着它对被代理类实现了哪些接口一无所知,也不能直接调用某个接口实现类中的方法实现,所以要有一个 Proxy 类,来告知 ProxyHandler 被代理类实现了哪些接口,并间接调用 ProxyHandler 中的代理方法,因为 Proxy 本身也不知道被代理类实现了哪些接口,所以需要在构造函数中传入 object.getClass().getInterfaces() 的结果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章