代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一个代理以控制对这个对象的访问。代理对象通常会对真实对象的请求进行一些处理(例如延迟初始化、访问控制、日志记录等),它能够在不改变目标对象的情况下,给目标对象添加额外的功能。
主要组成部分:
-
主题接口(Subject):
- 定义了真实对象和代理对象的共同接口。客户端通过这个接口与真实对象交互。
-
真实主题(Real Subject):
- 实现了主题接口,代表真实的对象,包含实际的业务逻辑。
-
代理(Proxy):
- 也是实现主题接口的类,它持有一个真实主题的引用,并对真实主题的请求进行处理。
优点:
-
控制访问:可以在代理类中添加访问控制逻辑,从而增强安全性。
-
延迟加载:代理对象可以在实际需要时才创建真实对象,提高性能。
-
更好的管理:可以通过代理对请求进行日志记录、缓存等管理。
-
透明性:客户端与真实对象之间的交互是透明的,因为它们通过相同的接口来访问。
使用场景:
- 当需要控制对某个对象的访问时(例如,权限控制)。
- 当需要在访问对象时进行附加操作时(如延迟加载)。
- 当需要对访问对象进行代理(如网络请求或缓存)。
静态代理
GO:
golang 实现静态代理,有 Golang 和 java 的差异性,我们无法比较方便的利用反射实现动态代理,但是我们可以利用** go generate **实现类似的效果,并且这样实现有两个比较大的好处,一个是有静态代码检查,我们在编译期间就可以及早发现问题,第二个是性能会更好
package proxyimport ("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 proxyimport ("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{@Overridepublic void login(String username, String password) {// 不做具体实现System.out.println("登陆成功");}
}
public class UserProxy implements IUser{private User user;@Overridepublic 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{@Overridepublic 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;}@Overridepublic 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 项目,添加相关依赖)。
- 创建一个代理工厂
- 创建代理对象
- 调用方法
... 模版代码就不加了.网上都有。