代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一个代理以控制对这个对象的访问。代理对象通常会对真实对象的请求进行一些处理(例如延迟初始化、访问控制、日志记录等),它能够在不改变目标对象的情况下,给目标对象添加额外的功能。
主要组成部分:
-
主题接口(Subject):
- 定义了真实对象和代理对象的共同接口。客户端通过这个接口与真实对象交互。
-
真实主题(Real Subject):
- 实现了主题接口,代表真实的对象,包含实际的业务逻辑。
-
代理(Proxy):
- 也是实现主题接口的类,它持有一个真实主题的引用,并对真实主题的请求进行处理。
优点:
-
控制访问:可以在代理类中添加访问控制逻辑,从而增强安全性。
-
延迟加载:代理对象可以在实际需要时才创建真实对象,提高性能。
-
更好的管理:可以通过代理对请求进行日志记录、缓存等管理。
-
透明性:客户端与真实对象之间的交互是透明的,因为它们通过相同的接口来访问。
使用场景:
- 当需要控制对某个对象的访问时(例如,权限控制)。
- 当需要在访问对象时进行附加操作时(如延迟加载)。
- 当需要对访问对象进行代理(如网络请求或缓存)。
静态代理
GO:
golang 实现静态代理,有 Golang 和 java 的差异性,我们无法比较方便的利用反射实现动态代理,但是我们可以利用** go generate **实现类似的效果,并且这样实现有两个比较大的好处,一个是有静态代码检查,我们在编译期间就可以及早发现问题,第二个是性能会更好
package proxy
import (
"fmt"
"log"
"time"
)
// IUser 接口
type IUser interface {
// Login 登陆函数
Login(username string, password string) error
}
// User 用户实现IUser接口
type User struct {
}
// Login 用户登录
func (u *User) Login(username string, password string) error {
// 不实现细节
fmt.Println("登陆成功......")
return nil
}
// UserProxy 代理类 也实现 IUser 接口
type UserProxy struct {
user *User
}
// NewUserProxy NewUserProxy
func NewUserProxy(user *User) *UserProxy {
return &UserProxy{
user: user,
}
}
func (u *UserProxy) Login(username string, password string) error {
// before 这里可能会有一些统计的逻辑
start := time.Now()
// 这里是原有的业务逻辑
if err := u.user.Login(username, password); err != nil {
return err
}
// after 这里可能也有一些监控统计的逻辑
log.Printf("user login cost time: %s", time.Now().Sub(start))
return nil
}
package proxy
import (
"github.com/stretchr/testify/require"
"testing"
)
func TestProxy(t *testing.T) {
// 构建代理对象
proxy := NewUserProxy(&User{})
//调用登陆
err := proxy.Login("test", "password")
require.Nil(t, err)
}
JAVA:
public interface IUser {
public void login(String username, String password);
}
public class User implements IUser{
@Override
public void login(String username, String password) {
// 不做具体实现
System.out.println("登陆成功");
}
}
public class UserProxy implements IUser{
private User user;
@Override
public void login(String username, String password) {
// 可以在请求之前进行某些处理
if (user == null) {
user = new User();
}
System.out.println("Proxy: Pre-processing before request.");
user.login(username, password); // 转发请求
System.out.println("Proxy: Post-processing after request.");
}
}
public class ProxyTest {
@Test(description = "静态代理")
public void proxyTest(){
UserProxy userProxy = new UserProxy();
userProxy.login("xxx", "yyy");
}
}
动态代理
GO:待补充。。。。
JAVA:
1. 基于 JDK 的动态代理
JDK 的动态代理通过 java.lang.reflect.Proxy
类和 InvocationHandler
接口来实现。它需要指定一个接口,然后通过代理对象来调用真实对象的方法。
使用步骤:
- 定义接口
- 创建真实主题类
- 实现
InvocationHandler
接口 - 创建代理对象
- 调用方法
//1.定义接口
public interface Subject {
public void request();
}
//2.创建真实主题类
public class RealSubject implements Subject{
@Override
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
//3.动态代理处理器 实现 InvocationHandler 接口
public class DynamicProxyHandler implements InvocationHandler {
private Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在调用目标方法之前执行一些操作
System.out.println("Proxy: Pre-processing before request.");
Object result = method.invoke(target, args); // 调用真实方法
// 在调用目标方法之后执行一些操作
System.out.println("Proxy: Post-processing after request.");
return result;
}
}
@Test(description = "动态代理-JDK")
public void dynamicJDKTest(){
RealSubject realSubject = new RealSubject();
Subject proxyInstance = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
new DynamicProxyHandler(realSubject)
);
proxyInstance.request();
}
2. 基于 CGLIB 的动态代理
CGLIB(Code Generation Library)是一种用于在运行时生成类的库,它通过继承来创建代理对象。CGLIB 适用于代理类没有接口的情况。
使用步骤:
- 添加 CGLIB 依赖(如果是 Maven 项目,添加相关依赖)。
- 创建一个代理工厂
- 创建代理对象
- 调用方法
... 模版代码就不加了.网上都有。