一天攻克一个知识点 —— 设计模式之动态代理

一、设计模式之代理设计

代理设计是在Java开发中使用较多的一种设计模式,所谓的代理设计模式就是指一个代理主体操作真实主体,真实主体操作具体业务,代理主体负责给具体业务添砖加瓦。

就好比在生活中你有一套房子想要出租(你=真实主体),你找了房产中介(中介=代理主体)。真实主体负责提供房屋和收钱,代理主体负责带客户看房 、扣除手续费。租客只管租房子和付款,至于谁提供的房子并不关心。

我们发现,只需要定义一个租赁的接口,真实主体与代理主体都可以实现此接口,然后再由代理主体操作真实主体即可,上面的要求可以形成如下的代码:

1. 定义租赁接口

java 复制代码
package com.javabasic.proxy;

/**
 * 定义抽象接口
 */
public interface House {

    /**
     * 定义抽象方法 租赁
     */
    void rent();
}

2. 定义真实主体 - 房东

java 复制代码
package com.javabasic.proxy;

/**
 * 定义真实主体 房东
 */
public class Owner implements House{

    @Override
    public void rent() {
        System.out.println("房东提供房子,收取租金200元/月");
    }
}

3. 定义代理主体 - 中介

java 复制代码
package com.javabasic.proxy;

/**
 * 定义代理主体 中介
 */
public class Agent implements House{

    // 接收真实主体 房东
    private House house;

    /**
     * 通过构造方法,让中介与房东之间产生联系。
     * 根据Java动态绑定机制,House运行时的真实类型是房东类型,就可以获取到房东的出租行为。
     * @param house
     */
    public Agent(House house){
        this.house = house;
    }

    /**
     * 中介对房东出租业务进行增强
     */
    @Override
    public void rent() {
        rentBefore();
        house.rent(); // 房东 出租
        rentAfter();
    }

    private void rentBefore(){
        System.out.println("中介负责寻找租客、带看、保存租客信息、签合同、收取租金。");
    }

    private void rentAfter(){
        System.out.println("中介负责租客退租后的清扫工作。");
    }

}

4. 主程序 中介出租房屋

二、动态代理

上面讲解的代理机制的操作,属于静态代理,因为每一个代理类只能为一个接口服务,这样程序开发中必然会产生过多的代理类。最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理功能。

Java 中想要实现动态代理的机制,则需要java.lang.reflect.InvocationHandler接口java.lang.reflect.Proxy类的支持。

InvocationHandler接口的定义如下:

java 复制代码
package java.lang.reflect;

public interface InvocationHandler {

    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类。

java 复制代码
	/*
		ClassLoader loader : 类加载器
		Class<?>[] interfaces : 得到真实类实现的全部接口
		InvocationHandler h : 得到InvocationHandler子类实例
	*/
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        ...
    }

房屋租赁代码修改如下 :

1. 需要房东实现租赁的接口

java 复制代码
public interface House {

    /**
     * 定义抽象方法 租赁
     */
    void rent();
}

public class Owner implements House{

    @Override
    public void rent() {
        System.out.println("房东提供房子,收取租金200元/月");
    }
}

2. 创建代理类(InvocationHandler / Proxy)

java 复制代码
package com.javabasic.proxy;

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

public class Agent2 implements InvocationHandler {

    // 接收真实主体
    private Object obj;

    // 对外提供绑定真实主体方法
    public Object bind(Object obj){
        this.obj = obj;
        // 通过真实对象创建代理对象并返回给调用者。
        /*
             Proxy.newProxyInstance : 三个参数
                    类加载器 :  this.obj.getClass().getClassLoader()
                    真实类型实现的所有接口 : this.obj.getClass().getInterfaces()
                    代理类  : this
             return 代理对象
         */
        Object object = Proxy.newProxyInstance(this.obj.getClass().getClassLoader(),
                this.obj.getClass().getInterfaces(), this);
        System.out.println("bind之后object真实类型 = " + object.getClass().getName());
        return object;
    }

    /**
     * 代理类会执行的方法。
     * @param proxy 代理主体
     * @param method 调用的方法
     * @param args 方法的参数
     *
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy真实类型 = " + proxy.getClass().getName());
        
        rentBefore();
        method.invoke(this.obj, args); // 通过反射执行真实主体方法
        rentAfter();
        return null;
    }

    private void rentBefore(){
        System.out.println("中介负责寻找租客、带看、保存租客信息、签合同、收取租金。");
    }

    private void rentAfter(){
        System.out.println("中介负责租客退租后的清扫工作。");
    }
}

3. 主程序 出租

相关推荐
2202_754421542 分钟前
生成MPSOC以及ZYNQ的启动文件BOOT.BIN的小软件
java·linux·开发语言
蓝染-惣右介5 分钟前
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
java·数据库·tomcat·mybatis
小林想被监督学习5 分钟前
idea怎么打开两个窗口,运行两个项目
java·ide·intellij-idea
HoneyMoose7 分钟前
IDEA 2024.3 版本更新主要功能介绍
java·ide·intellij-idea
我只会发热9 分钟前
Java SE 与 Java EE:基础与进阶的探索之旅
java·开发语言·java-ee
是老余10 分钟前
本地可运行,jar包运行错误【解决实例】:通过IDEA的maven package打包多模块项目
java·maven·intellij-idea·jar
crazy_wsp11 分钟前
IDEA怎么定位java类所用maven依赖版本及引用位置
java·maven·intellij-idea
.Ayang13 分钟前
tomcat 后台部署 war 包 getshell
java·计算机网络·安全·web安全·网络安全·tomcat·网络攻击模型
一直学习永不止步19 分钟前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
hummhumm33 分钟前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j