

设计模式——代理模式_大鱼的技术博客_51CTO博客
source link: https://blog.51cto.com/learningfish/5398750
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

- 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
- 当一个复杂对象的多份副本须存在时,代理模式可以结合享元模式以减少存储器用量。典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象。而作用在代理者的运算会转送到原本对象。一旦所有的代理者都不存在时,复杂对象会被移除。
- 代理模式有不同的形式,主要有三种静态代理、动态代理(JDK 代理、接口代理)和Cglib 代理(可以在内存动态的创建对象,而不需要实现接口,他是 属于动态代理的范畴)。
UML类图

类图解析:
Subject:通过接口或抽象类声明真实角色实现的业务方法。
Proxy:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
RealSubject:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
背景介绍:老师生病了,需要另一名老师帮其代课

ITeacherDao接口类
public interface ITeacherDao {
/**
* 老师上课
*/
void teach();
}
TeacherDao实现类
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
System.out.println("开始上课...");
}
}
TeacherDaoProxy代理类
public class TeacherDaoProxy implements ITeacherDao{
// 被代理对象
private ITeacherDao iTeacherDao;
public TeacherDaoProxy(ITeacherDao iTeacherDao) {
this.iTeacherDao = iTeacherDao;
}
public TeacherDaoProxy() {
try {
iTeacherDao =(ITeacherDao) this.getClass().getClassLoader().loadClass("com.xy.staticproxy.TeacherDao").newInstance();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
/**
* 上课前
*/
public void preTeach() {
System.out.println("你们老师生病了, 我来代一节课...");
}
@Override
public void teach() {
preTeach();
iTeacherDao.teach();
afterTeach();
}
/**
* 上课后
*/
private void afterTeach() {
System.out.println("下课了, 同学们有缘再见...");
}
}
Client测试类
public class Client {
public static void main(String[] args) {
// 生病的老师, 被代理对象
ITeacherDao patientTeacher = new TeacherDao();
// 新老师, 代理对象
//ITeacherDao proxyTeacher = new TeacherDaoProxy(patientTeacher);
TeacherDaoProxy proxyTeacher = new TeacherDaoProxy();
// 老师代课
proxyTeacher.teach();
}
}
实现效果:

静态代理优缺点
- 优点:在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展。
- 缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类一旦接口增加方法,目标对象与代理对象都要维护
动态代理模式的基本介绍
- 代理对象,不需要实现接口,但是目标对象要实现接口,否则不能用动态代理。
- 代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象动态代理也叫做: JDK代理、接口代理。

ITeacherDao接口类
public interface ITeacherDao {
/**
* 老师上课
*/
void teach();
}
TeacherDao实现类
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
System.out.println("开始上课...");
}
}
ProxyFactory代理类
public class ProxyFactory{
// 目标对象
private Object target;
// 构造器,对target进行初始化
public ProxyFactory(Object target) {
this.target = target;
}
/**
* 方法执行前
*/
public void preMethod() {
System.out.println("方法执行前...");
}
/**
* 方法执行后
*/
private void afterMethod() {
System.out.println("方法执行后...");
}
// 给目标对象生成代理对象
public Object getProxyInstance() {
/**
* ClassLoader loader, 指定类加载器
* Class<?>[] interfaces,目标对象(被代理对象),使用泛型方式确认类型
* InvocationHandler h 事件处理执行目标对象的方法时,会触发时间处理器的方法
* 会把当前执行的目标对象方法作为参数传入
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
preMethod();
// 反射机制调用目标对象方法
Object invoke = method.invoke(target, args);
afterMethod();
return invoke;
});
}
}
Test用于测试动态代理效果
public interface Test {
void test();
}
Client测试类
public class Client {
public static void main(String[] args) {
// 被代理对象
TeacherDao target = new TeacherDao();
// 创建代理对象
ITeacherDao proxyITeacher = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
proxyITeacher.teach();
System.out.println("-------------");
Test test = (Test)new ProxyFactory((Test) () ->
System.out.println("this is a test")
).getProxyInstance();
test.test();
}
}
测试结果:

cglib代理
Cglib代理模式的基本介绍
-
静态代理和JDK代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理,即Cglib代理。
-
Cglib代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展,有些书也将Cglib代理归属到动态代理。
-
Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP,实现方法拦截。
-
在AOP编程中如何选择代理模式:
- 目标对象需要实现接口,用JDK代理
- 目标对象不需要实现接口,用Cglib代理
-
Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类

导入cglib依赖jar包
`ProxyFactoryd代理工厂
public class ProxyFactory implements MethodInterceptor {
// 维护一个目标对象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
/**
* 返回一个target代理对象
* @return
*/
public Object getProxyInstance() {
// 1、创建一个工具类
Enhancer enhancer = new Enhancer();
// 2、设置父类
enhancer.setSuperclass(target.getClass());
// 3、设置回调函数
enhancer.setCallback(this);
// 4、返回子类,即代理对象
return enhancer.create();
}
/**
* 方法执行前
*/
public void preMethod() {
System.out.println("方法执行前...");
}
/**
* 方法执行后
*/
private void afterMethod() {
System.out.println("方法执行后...");
}
// 重写拦截方法,调用目标方法
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
preMethod();
// 使用反射
//Object value = method.invoke(target, objects);
// 使用fastClass
Object value = methodProxy.invokeSuper(o, objects);
afterMethod();
return value;
}
}
TeacherDao和Test(被代理类)
public class TeacherDao {
public void teach() {
System.out.println("老师授课中...");
}
}
class Test{
public void test() {
System.out.println("this is a teat...");
}
}
Client测试类
public class Client {
public static void main(String[] args) {
// 被代理类
TeacherDao target = new TeacherDao();
// 创建对象代理
TeacherDao proxyTeacher =(TeacherDao) new ProxyFactory(target).getProxyInstance();
// 执行方法
proxyTeacher.teach();
System.out.println("----------");
// 测试类
((Test)new ProxyFactory(new Test()).getProxyInstance()).test();
}
}
测试结果:

几种常见的代理模式介绍——几种变体
- 防火墙代理:内网通过代理穿透防火墙,实现对公网的访问。
- 缓存代理:比如:当请求图片文件等资源时,先到缓存代理取,如果取到资源则ok,如果取不到资源,再到公网或者数据库取,然后缓存。
- 远程代理:远程对象的本地代表,通过它可以把远程对象当本地对象来调用。远程代理通过网络和真正的远程对象沟通信息。
- 同步代理:主要使用在多线程编程中,完成多线程间同步工作
Recommend
-
11
设计模式基础 设计模式简介 软件工程中,设计模式(design pattern)是对软件中普遍存在(反复出现)的各种问题,所提出的解决方案,是由Erich Gamma、Richard Helm、Ralph J...
-
7
单例设计模式介绍 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对 象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。 单例设计模式八种方式
-
7
基本介绍 原型模式(Prototype模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。...
-
7
建造者模式(Builder Pattern)又叫生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。 建造者模式是一步一步创建一个复杂...
-
6
设计模式——适配器模式 推荐 原创 爱学习的大鱼 2022-06-14 08:38:37
-
2
设计模式——组合模式 原创 爱学习的大鱼 2022-06-17 08:51:33...
-
8
命令模式(Command Pattern) :在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计。 命名模式使得...
-
7
设计模式——状态模式 原创 爱学习的大鱼 2022-06-30 08:24:12...
-
6
JWT简介 JWT(Json Web Token)通过json形式,作为web应用中的令牌,用于在各方之间安全地将信息作为json对象创数,在数据的传输过程中还可以完成数据的加密、签名等相关处理,特点如下: 跨语言:支持主流语言 ...
-
6
SnowFlake 介绍 SnowFlake 中文意思为雪花,故称为雪花算法。 最早是 Twitter 公司在其内部用于分布式环境下生成唯一 ID。 2014年开源 scala 语言版本。
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK