代理模式(Proxy Pattern)__动态代理

一、为什么需要动态代理

1.为了解决静态代理一次只能服务一种类型的目标对象的问题
2.通过使用动态代理,可以在运行时动态获取一个持有目标对象,同时实现代理接口的代理对象实例,最后统一调用代理对象的 invoke() 方法,在此可以统一为所有代理接口方法注入相同的拓展逻辑

二、相关角色

接口对象:目标对象的抽象接口
目标对象:真实目标对象
代理对象:动态生成目标对象的代理对象

三、使用案例

接口对象:

/**
 * 目标对象的抽象接口
 */
public interface IDinner {

    /**
     * 定义目标对象的接口方法
     */
    void dinner();

}

目标对象:

/**
 * 目标对象,被代理的对象,实现了目标对象的抽象接口
 */
public class DinnerConsumer implements IDinner {

    @Override
    public void dinner() {  
        System.out.println("只管吃大餐");
    }

}

调用处理器类:

/**
 * 调用处理器类,生成动态代理对象
 */
public class DinnerHandler implements InvocationHandler {

    /**
     * 声明目标对象
     * 作用:绑定关系,关联到哪个接口(与具体的实现类绑定)的哪个方法将(具体的实现类的方法)被调用,执行 invoke() 方法
     */
    private Object target;

    // 构造代理对象时传入目标对象
    public DinnerHandler(Object target) {
        this.target = target;
    }

    public Object newProxyInstance(Object target) {
        /**
         * 参数一:指定为和目标对象同一个类加载器
         * 参数二:指定为目标对象实现的接口,代理对象默认实现了该接口,这样就能调用接口中的方法
         * 参数三:指定 InvocationHandler 对象,即动态代理在调用方法时会关联到哪个 InvocationHandler 对象
         * 最终生成动态代理类实例
         */
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 调用目标方法前的处理
        System.out.println("动态代理,有人请客");
        // 调用目标对象的方法
        method.invoke(target, args);
        // 调用目标方法后的处理
        System.out.println("动态代理,有人结账");
        return null;
    }

}

测试类:

public class DinnerTest {

    public static void main(String[] args) {
        //创建目标对象
        DinnerConsumer dinnerProvider = new DinnerConsumer();
        //创建代理对象
        InvocationHandler dinnerHandler = new DinnerHandler(dinnerProvider);
        //动态获取接口对象对应的代理对象实例 
        IDinner iDinner = (IDinner) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class<?>[] { IDinner.class }, dinnerHandler);
        //实际执行了 invoke() 方法,invoke() 方法通过反射机制调用真实目标对象的方法
        iDinner.dinner();
    }

}

猜你喜欢

转载自blog.csdn.net/qq_21586317/article/details/80396732
今日推荐