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

一、设计模式之代理设计

代理设计是在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. 主程序 出租

相关推荐
Otaku love travel5 分钟前
老系统改造增加初始化,自动化数据源配置(tomcat+jsp+springmvc)
java·tomcat·初始化·动态数据源
DKPT19 分钟前
Java设计模式之行为型模式(责任链模式)介绍与说明
java·笔记·学习·观察者模式·设计模式
L_autinue_Star34 分钟前
手写vector容器:C++模板实战指南(从0到1掌握泛型编程)
java·c语言·开发语言·c++·学习·stl
晨岳1 小时前
CentOS 安装 JDK+ NGINX+ Tomcat + Redis + MySQL搭建项目环境
java·redis·mysql·nginx·centos·tomcat
执笔诉情殇〆1 小时前
前后端分离(java) 和 Nginx在服务器上的完整部署方案(redis、minio)
java·服务器·redis·nginx·minio
YuTaoShao1 小时前
【LeetCode 热题 100】24. 两两交换链表中的节点——(解法一)迭代+哨兵
java·算法·leetcode·链表
程序员的世界你不懂1 小时前
(20)Java+Playwright自动化测试- 操作鼠标拖拽 - 上篇
java·python·计算机外设
AI360labs_atyun2 小时前
Java在AI时代的演进与应用:一个务实的视角
java·开发语言·人工智能·科技·学习·ai
不像程序员的程序媛2 小时前
redis的一些疑问
java·redis·mybatis
知其然亦知其所以然3 小时前
Java 面试高频题:GC 到底回收了什么、怎么回收、啥时候回收?
java·后端·面试