目录
[TOC]
什么是代理模式
代理设计模式是一种结构型设计模式,它允许你控制对一个对象的访问。该模式通过在客户端和目标对象之间创建一个代理来实现这一目的。代理可以提供额外的功能,例如安全性、缓存、日志记录等。代理可以在运行时动态地添加或删除功能,从而使系统更加灵活。
代理模式通常包括以下几个角色:
- 抽象角色:定义了代理接口,并提供了一些基本的方法。
- 委托角色:实现了抽象角色中定义的方法,并提供了与目标对象相同的接口。
- 目标角色:被代理的对象,也就是需要被保护或者控制访问的对象。
代理模式可以分为静态代理和动态代理两种类型。静态代理是在编译时生成代理类,而动态代理是在运行时动态生成代理类。
应用场景
- 远程方法调用(Remote Method Invocation,RMI):在分布式系统中,客户端可以通过代理对象来调用远程对象的方法。
- 动态代理:动态代理可以在运行时生成代理对象,从而实现更灵活的代码重用和扩展。
- 缓存:代理可以用于缓存数据,以提高性能并减少对数据库或其他存储系统的访问。
- 安全控制:代理可以用于实现安全控制,例如,一个代理服务器可以检查客户端的身份验证信息,以确保只有授权的用户才能访问受保护的资源。
- 日志记录:代理可以用于记录系统的行为,例如,代理服务器可以记录所有被代理对象的方法调用。
- 对象池:代理可以用于管理对象池,例如,代理服务器可以维护一组对象的池,并在需要时从池中获取对象而不是每次都创建新的对象。
- 延迟加载:代理可以用于延迟加载资源,例如,当需要使用某个资源时才加载它,而不是在程序启动时就加载。
- 命令注入:代理可以用于注入命令,例如,在一个系统中,客户端可以通过代理对象来执行特定的命令。
- 智能指针:智能指针是一种基于代理模式实现的指针类型,它可以自动管理内存并避免内存泄漏。
- 装饰器模式:装饰器模式也可以通过代理来实现,例如,一个装饰器可以包装一个对象并添加额外的功能。
- 买火车票不一定到火车站买,也可以去代售点。
- 银行卡和支票都是真实钱的代理对象。
静态代理
静态代理是一种在代码编写期进行代理类和被代理类的关联的代理方式。
具体实现是创建一个代理类,通常需要实现与被代理类相同的接口或继承被代理类。
房东接口类:Landlord1Service,注意,静态代理实现它的真实对象只能有一个,多个的话,代理对象不能确定哪个对象需要被代理,会导致报错,JDK动态代理没这个问题。
代码结构

代码
房东接口
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | 
 
 public interface Landlord1Service {
 
 
 
 
 
 void rent(Integer money);
 }
 
 | 
租客
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | import org.springframework.stereotype.Component;
 
 
 
 @Component
 public class TenantImpl implements Landlord1Service {
 
 @Override
 public void rent(Integer money) {
 System.out.println("租下" + money + "元一个月的房子");
 }
 }
 
 | 
中介
中介这个时候就相当于代理
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;
 
 
 
 
 
 
 @Component
 public class ProxyImpl implements Landlord1Service {
 
 
 
 
 @Autowired
 private Landlord1Service target;
 
 
 
 
 
 
 
 @Override
 public void rent(Integer money) {
 System.out.println("[静态代理]交中介费");
 target.rent(money);
 System.out.println("[静态代理]中介负责维修管理");
 }
 }
 
 | 
测试
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
 @SpringBootTest
 public class TestProxy {
 
 
 
 
 @Autowired
 private TenantImpl tenant;
 
 
 
 
 @Autowired
 private ProxyImpl proxy;
 
 
 @Test
 void TestStatic() {
 tenant.rent(1000);
 System.out.println();
 proxy.rent(2000);
 }
 }
 
 | 

静态代理应用场景
适用场景:
- 当代理对象只有一个时,可以使用静态代理
- 当被代理的类的接口比较稳定时,可以使用静态代理
- 当需要为多个被代理的类提供代理时,会导致代理类过多,不方便管理和维护,所以不建议使用静态代理。
JDK动态代理
JDK动态代理是一种比较常见的代理方式,它是在程序运行时动态生成代理类,也就是说我们在编写代码时并不知道具体代理的是什么类,而是在程序运行时动态生成。
代码结构

代码
房东接口
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | 
 
 public interface Landlord2Service {
 
 
 
 
 void rent(Integer money);
 }
 
 | 
租客1
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | import org.springframework.stereotype.Component;
 
 
 
 @Component
 public class Teant1Impl implements Landlord2Service {
 @Override
 public void rent(Integer money) {
 System.out.println("tenant1租下" + money + "元一个月的房子");
 }
 }
 
 | 
租客2
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | import org.springframework.stereotype.Component;
 
 
 
 @Component
 public class Tenant2Impl implements Landlord2Service {
 @Override
 public void rent(Integer money) {
 System.out.println("tenant2租下" + money + "元一个月的房子");
 }
 }
 
 | 
中介
中介—动态代理类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | import java.lang.reflect.Proxy;
 
 
 
 public class JDKProxy {
 
 private Object target;
 
 public JDKProxy(Object target) {
 this.target = target;
 }
 
 
 
 
 
 
 public Object getProxyInstance() {
 return Proxy.newProxyInstance(target.getClass().getClassLoader(),
 target.getClass().getInterfaces(),
 
 (proxy, method, args) -> {
 
 System.out.println("[JDK动态代理]交中介费");
 method.invoke(target, args);
 System.out.println("[JDK动态代理]中介负责维修管理");
 return null;
 });
 }
 }
 
 | 
测试
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 
 | import com.xiaofei.proxy.jdkProxy.JDKProxy;import com.xiaofei.proxy.jdkProxy.Landlord2Service;
 import com.xiaofei.proxy.jdkProxy.Teant1Impl;
 import com.xiaofei.proxy.jdkProxy.Tenant2Impl;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
 
 
 
 @SpringBootTest
 public class JDKProxyTest {
 @Autowired
 private Teant1Impl teant1;
 @Autowired
 private Tenant2Impl tenant2;
 
 
 @Test
 void TestJDK() {
 Landlord2Service proxyInstance1 = (Landlord2Service) new JDKProxy(teant1).getProxyInstance();
 proxyInstance1.rent(2500);
 
 System.out.println();
 Landlord2Service proxyInstance2 = (Landlord2Service) new JDKProxy(tenant2).getProxyInstance();
 proxyInstance2.rent(2500);
 }
 }
 
 | 

JDK动态代理应用场景
- 对象必须实现一个或多个接口
- 代理类的代理方法不需要额外的逻辑
Cglib代理
CGLIB代理是在运行时动态生成代理类的方式,它使用的库是cglib,和JDK代理相比,它不是动态的生成一个实现了接口的代理类,而是直接在内存中构建一个被代理类的子类,并重写父类的方法来进行代理。
代码结构
代码
房东
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | import org.springframework.stereotype.Component;
 
 
 
 @Component
 public class Landlord3Service {
 
 
 
 
 
 
 public void rent(Integer money) {
 System.out.println("租下" + money + "元一个月的房子");
 }
 }
 
 | 
Cglib代理
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 
 | import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;
 import org.springframework.cglib.proxy.MethodProxy;
 
 import java.lang.reflect.Method;
 
 
 
 
 
 
 public class CglibProxy implements MethodInterceptor {
 
 
 
 
 private final Object target;
 
 public CglibProxy(Object target) {
 this.target = target;
 }
 
 public Object getProxyInstance() {
 
 Enhancer en = new Enhancer();
 
 en.setSuperclass(target.getClass());
 
 en.setCallback(this);
 
 return en.create();
 }
 
 @Override
 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
 System.out.println("[Cglib代理]交中介费");
 method.invoke(target, objects);
 System.out.println("[Cglib代理]中介负责维修管理");
 return null;
 }
 }
 
 | 
测试
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | import com.xiaofei.proxy.cglib.CglibProxy;import com.xiaofei.proxy.cglib.Landlord3Service;
 import lombok.RequiredArgsConstructor;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
 
 
 
 @SpringBootTest
 @RequiredArgsConstructor
 public class CglibProxyTest {
 @Autowired
 private Landlord3Service landlord3Service;
 
 
 
 
 @Test
 void TestCglib() {
 Landlord3Service proxyInstance = (Landlord3Service) new CglibProxy(landlord3Service).getProxyInstance();
 proxyInstance.rent(3000);
 }
 }
 
 | 

Cglib代理应用场景
- 被代理的类没有实现接口或者无法实现接口
- 代理类的代理方法需要进行额外的逻辑,如事务处理等。
总结
优点:
- 代理模式可以隐藏真是对象的实现细节,使客户端无需知晓真实对象的工作方式和结构。
- 通过代理类来间接访问真实类,可以在不修改真实类的情况下,对其进行扩展、优化或添加安全措施。
- 代理模式实现起来简单,易于扩展和维护,符合面向对象设计原则中的开闭原则。
缺点:
- 代理模式可能会引入额外的复杂性和间接性,增加程序设计和维护的难度。
- 对象代理可能会降低系统性能,特别是在处理大数据量或频繁调用的情况下,因为代理需要额外的计算和网络通信开销。