当前位置:网站首页>代理模式详解
代理模式详解
2022-06-24 19:30:00 【伏加特遇上西柚】
代理模式详解
1、代理模式概念
我很忙,忙的没空理你,那你要找我呢,就先找我的代理人吧,那代理人总要知道被代理人能做哪些事情不能做哪些事情吧,那就是两个人具备同一个接口,被代理人虽然不想干活,但是代理的人能干活呀。
生活中的房屋中介

2、代理模式分类
静态代理:
【定义】
在程序运行之前,代理类.class文件就已经被创建
【实现】
由程序员创建或特定工具自动生成源代码,在对其编译
动态代理:
【定义】
程序运行时通过反射机制动态创建的,对方法的【增强】,不需要修改源码
【实现】
基于接口:JDK动态代理
基于子类:CGLib动态代理
2.1 静态代理
【1】目标
使用静态代理的方式,完成通过房产中介租房的操作;
【2】实现
生活中的房屋中介抽象:

步骤:
1、创建项目;
2、定义接口:HouseAgencyCompany及接口中租房的方法:rentingHouse;
3、定义房主类:HouseOwner 中介类 HouseProxy均实现接口HouseAgencyCompany;
4、租客类Customer调用HouseProxy完成租房
【2.2】定义HouseAgencyCompany
package com.test.spring;
/** * @Description:中介公司 */
public interface HouseAgencyCompany {
/** * @Description 租房子 */
void rentingHouse();
}
【2.3】定义HouseOwner、HouseProxy
package com.test.spring;
/** * @Description:房东 */
public class HouseOwner implements HouseAgencyCompany {
@Override
public void rentingHouse() {
System.out.println("房东:签合同");
}
}
package com.test.spring;
/** * @Description:中介 */
public class HouseProxy implements HouseAgencyCompany{
private HouseOwner houseOwner;
public HouseProxy() {
this.houseOwner = new HouseOwner();
}
@Override
public void rentingHouse() {
System.out.println("中介:我带你去看房子");
System.out.println("中介:这个房子价格很便宜");
houseOwner.rentingHouse();
System.out.println("中介:欢迎下次光临");
}
}
【2.4】定义Customer
package com.test.spring;
import org.junit.Test;
/** * @Description:租客 */
public class Customer {
@Test
public void needHouse(){
HouseOwner houseOwner = new HouseOwner();
houseOwner.rentingHouse();
System.out.println("=============================");
HouseAgencyCompany houseAgencyCompany = new HouseProxy();
houseAgencyCompany.rentingHouse();
}
}
【2.5】运行结果
2.2 动态代理概述
代理类在程序运行时创建的方式被成为动态代理。也就是说,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的动态生成的。相比于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。
2.2.1 jdk动态代理
2.2.1.1 jdk动态代理:
被代理的类必须基于接口
java.lang.reflect.Proxy:
Java动态代理机制的主类,提供了一组静态方法来为一组接口动态地生成代理类及其实例。
//方法1: 该方法用于获取指定动态代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy)
//方法2:该方法用于获取关联于指定类装载器和一组接口的动态代理对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces)
//方法3:该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl)
//方法4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理对象:1、类加载器 2、接口数组、调用处理器(增强部分的业务代码)
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
java.lang.reflect.InvocationHandler:
调用处理器接口,它自定义了一个invoke方法,用于集中处理在动态代理对象上的方法调用,通常在该方法中实现对委托类的代理访问。每次生成动态代理对象时都需要指定一个实现了该接口的调用处理器对象。
InvocationHandler的核心方法:
//该方法负责集中处理动态代理类上的所有方法调用。
//第一个参数是代理对象,第二个参数是被调用的方法对象,第三个方法是调用参数。
//调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行。
Object invoke(Object proxy, Method method, Object[] args)

2.2.1.2 实现
2.2.1.2.1 代理接口
/** * @Description:中介公司 */
public interface HouseAgencyCompany {
/** * @Description 租房子 */
void rentingHouse();
}
2.2.1.2.2 房东类实现代理接口
/** * @Description:房东 */
public class HouseOwner implements HouseAgencyCompany {
@Override
public void rentingHouse() {
System.out.println("房东:签合同");
}
}
2.2.1.2.3 消费者类
/** * @Description:租客 */
public class Customer {
HouseOwner houseOwner = new HouseOwner();
@Test
public void needHouse(){
System.out.println("=============================");
//第一个参数:目标类的加载器,第二个参数:目标类的接口,第三个参数:调用处理器
HouseAgencyCompany houseAgencyCompany = (HouseAgencyCompany) Proxy.newProxyInstance(
HouseAgencyCompany.class.getClassLoader(),
houseOwner.getClass().getInterfaces(),
new InvocationHandler() {
//第一个参数:代理类,
//第二个参数:执行的目标方法,这里指的是:rentingHouse
//第三参数:方法参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置增强
System.out.println("中介公司:我安排中介带你去看房子");
Object invoke = method.invoke(houseOwner, args);
//后置增强
System.out.println("中介公司:欢迎下次光临");
return invoke;
}
});
houseAgencyCompany.rentingHouse();
}
}
2.2.1.2.4 结果

2.2.2 cglib动态代理
2.2.2.1 思考
如果目标类没有实现接口呢?
那么就无法使用JDK的动态代理,因此这种方式有其局限性,必须实现一个接口。
可以使用的方案:
使用CGLIB动态代理:基于子类(包含本类)
net.sf.cglib.proxy.Enhancer
Enhancer类是CGLib中的一个字节码增强器,作用用于生成代理对象,跟上一章所学的Proxy类相似,常用方式为:
//方法1:该方法用于为指定目标类、回调对象 1、类的类型,2、调用处理器
public static Object create(Class type, Callback callback)
net.sf.cglib.proxy.MethodInterceptor
///第一个:代理类,第二个是:执行的目标方法,第三个:方法参数,第四个:方法的代理
Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
2.2.2.2实现
2.2.2.2.1房东类
/** * @Description:房东 */
public class HouseOwner {
public void rentingHouse() {
System.out.println("房东:签合同");
}
}
2.2.2.2.2消费者类
/** * @Description:租客 */
public class Customer {
@Test
public void needHouse(){
//第一个参数:被代理类的类型 第二个参数:拦截方法
HouseOwner houseOwner = (HouseOwner) Enhancer.create(
HouseOwner.class,
new MethodInterceptor() {
@Override
//第一个:代理类,第二个是:执行的目标方法,第三个:方法参数,第四个:方法的代理
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("房东儿子:我爸身体不好,让我来带i看房子");
methodProxy.invokeSuper(o, objects);
System.out.println("房东儿子:我爸身体不好,后面有什么事情你可以找我");
return null;
}
});
houseOwner.rentingHouse();
}
}
2.2.2.2.3结果

2.2.2.3小结
1、Cglib动态代理:基于类,无需实现接口;
2、被代理的目标类不能被final修饰
2.2.3动态代理小结
通过动态代理可以完成对已有方法的功能的增强:
1、JDK动态代理
要求:
被代理对象至少实现一个接口
应用场景:
被代理对象有接口
2、CGLIB动态代理
要求:
被代理类上不能用static、final修饰
应用场景:
被代理对象没有实现接口
边栏推荐
- After Firefox drag and drop, Baidu search will always be opened by default. If it is a picture, the picture will be opened.
- 是真干不过00后,给我卷的崩溃,想离职了...
- Summary of papers on traveling salesman problem (TSP)
- leetcode-201_2021_10_17
- Yida technology signed a contract with seven wolves to help the digital transformation of "Chinese men's wear leader"
- Introduce the overall process of bootloader, PM, kernel and system startup
- 基于kruskal的最小生成树
- Practice of hierarchical management based on kubesphere
- TCP RTT测量妙计
- [notes of Wu Enda] multivariable linear regression
猜你喜欢

我国SaaS产业的发展趋势与路径
![[精选] 多账号统一登录,你如何设计?](/img/df/9b4fc11a6971ebe8162ae84250a782.png)
[精选] 多账号统一登录,你如何设计?
![[camera Foundation (I)] working principle and overall structure of camera](/img/5d/c29d636a90d01e5c3852df2a0dd833.png)
[camera Foundation (I)] working principle and overall structure of camera

Maximum flow problem

The collection of zero code enterprise application cases in various industries was officially released
![[notes of Wu Enda] multivariable linear regression](/img/b1/60a702aaca58b0afa57ac2f552dabf.png)
[notes of Wu Enda] multivariable linear regression

Interviewer: you said you are proficient in redis. Have you seen the persistent configuration?

leetcode_191_2021-10-15

Reduce the pip to the specified version (upgrade the PIP through pycharm, and then reduce it to the original version)

PyCharm 中出现Cannot find reference ‘imread‘ in ‘__init__.py‘
随机推荐
【吴恩达笔记】机器学习基础
多线程收尾
Reduce the pip to the specified version (upgrade the PIP through CMP and reduce it to the original version)
How to refine permissions to buttons?
旅行商问题(TSP)的相关论文总结
C语言-关键字1
想当测试Leader,这6项技能你会吗?
《各行业零代码企业应用案例集锦》正式发布
优雅的自定义 ThreadPoolExecutor 线程池
Binary search tree template
架构实战营 第 6 期 毕业设计
[notes of Wu Enda] multivariable linear regression
降低pip到指定版本(通过cmp升级pip,在降低到原来版本)
【论】Deep learning in the COVID-19 epidemic: A deep model for urban traffic revitalization index
Transport layer UDP & TCP
并查集+建图
Installing Oracle without graphical interface in virtual machine centos7 (nanny level installation)
[notes of Wu Enda] convolutional neural network
【无标题】
如何做到全彩户外LED显示屏节能环保