栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

万能的动态代理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

万能的动态代理

一 点睛

在静态代理中,真实对象和代理角色是“一对一”的关系。而在动态代理中,真实对象和代理角色是“多对一”的关系。动态代理可以用一个“万能”的代理者来代理任何类型的真实对象,而不用像静态代理那样给每个真实角色都设置一个代理,这也是动态代理的最大优势。

静态代理需要实现和真实对象相同的接口。例如,房屋中介和真正房屋的主人,都需要“出租房”,因此“出租房”就是两者需要共同实现的接口。但是,动态代理既然是一个“万能”的代理者,那么动态代理应该实现什么接口呢?例如,房屋主人和汽车主人,都需要动态代理,那么这个动态代理应该实现“出租房”还是“出租车”的接口呢?为了解决这个问题,JDK 提供了一个“万能”的动态代理接口——InvocationHandler,及使用动态代理时可用  InvocationHandler 接口中的 invoke() 方法代理出租房、出租车等各种业务方法。

二 代码 1 租房接口
package dynamicproxy;

// 租房接口
public interface Subject {
    boolean rent(int money);
}
2 租车接口
package dynamicproxy;

// 出租车接口
public interface Subject2 {
    boolean rentCar(String type);
}
3 租房真实角色
package dynamicproxy;

// 租房真实角色
public class RealSubject implements Subject {
    @Override
    public boolean rent(int money) {
        System.out.println("租房" + money + "元");
        return true;
    }
}
4 租车真实角色
package dynamicproxy;

// 租车真实接口
public class RealSubject2 implements Subject2 {
    @Override
    public boolean rentCar(String type) {
        System.out.println("租用的车类型:" + type);
        return true;
    }
}
5 动态代理角色
package dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;


public class DynamicProxy implements InvocationHandler {
    private Object obj; // 可以代理任意 类型的角色

    public DynamicProxy(Object obj) {
        this.obj = obj;
    }

    public void before() {
        System.out.println("before rent()...");
    }

    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        this.before();
        // obj.method(args)
        boolean result = (boolean) (method.invoke(obj, args)); // 通过反射调用rent()方法
        this.after();
        return result;
    }

    public void after() {
        System.out.println("after...");
    }
}
6 租房测试
package dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) {
        // 真实对象
        Subject realSubject = new RealSubject();
        // 初步的代理对象:handler 就是真实角色 realSubject 的初步代理对象
        InvocationHandler handler = new DynamicProxy(realSubject);

        // 最终的代理对象
        
        Subject subProxy = (Subject) Proxy.newProxyInstance(
                handler.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                handler);
        boolean result = subProxy.rent(3000); // 会调用动态代理对象的 invoke()
        System.out.println(subProxy.getClass().getName());
        System.out.println(result ? "ok" : "error");
    }
}
7 租车测试
package dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Test2 {
    public static void main(String[] args) {

        Subject2 realSubject2 = new RealSubject2();
        InvocationHandler handler2 = new DynamicProxy(realSubject2);
        Subject2 subProxy2 = (Subject2) Proxy.newProxyInstance(
                handler2.getClass().getClassLoader(),
                realSubject2.getClass().getInterfaces(),
                handler2);
        subProxy2.rentCar("宝马");
    }
}
三 测试 1 租房测试

before rent()...

租房3000元

after...

com.sun.proxy.$Proxy0

ok

2 租车测试

before rent()...

租用的车类型:宝马

after...

四 动态代理的编写步骤

1 编写自定义接口。接口本身包含了真实角色中的方法(称为方法A)。

2 编写真实角色类。真实角色类需要实现自定义接口,并重写接口中的方法A。

3 编写动态代理角色类。动态代理角色类实现 InvocationHandler 接口,并重写接口中的 invoke() 方法,再通过 method.invoke(obj,args)调用真实角色中的方法A。

4 使用时,先根据真实角色,产生一个初步代理角色 handler,即 handler = new DynamicProxy(真实角色);再通过 subProxy = (自定义接口) Proxy.newProxyInstance(类加载器,真正角色接口数组,初步代理角色)产生一个最终的代理对象 subProxy;最后通过 subProxy 调用真实角色方法 A,但实际上,在调用代理角色方法的 invoke() 方法。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/874028.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号