ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【计划模式】代理模式 [打印本页]

作者: 美丽的神话    时间: 2024-11-26 22:29
标题: 【计划模式】代理模式
一、什么是代理模式

概念:


分类:

代理模式的脚色构成:

代理模式中的客户端通过与代理对象举行交互,而代理对象负责将哀求转发给真实主题对象。客户端无需直接与真实主题对象打交道,而是通过代理对象来举行间接访问。这样做的好处是可以在代理对象中添加一些额外的功能,同时也可以对真实主题对象举行访问控制,提高了体系的灵活性和安全性。
二、代理模式的Java实现示例

1、静态代理的实现

起首定义一个接口 Subject,包罗一个方法 request():
  1. public interface Subject {
  2.     void request();
  3. }
复制代码
然后创建一个真实的对象 RealSubject,实现 Subject 接口:
  1. public class RealSubject implements Subject {
  2.     @Override
  3.     public void request() {
  4.         System.out.println("真实的对象处理请求");
  5.     }
  6. }
复制代码
接着创建一个代理对象 ProxySubject,同样实现 Subject 接口,并持有一个真实对象的引用:
  1. public class ProxySubject implements Subject {
  2.     private RealSubject realSubject;
  3.     public ProxySubject(RealSubject realSubject) {
  4.         this.realSubject = realSubject;
  5.     }
  6.     @Override
  7.     public void request() {
  8.         System.out.println("代理对象处理请求之前的操作");
  9.         realSubject.request();
  10.         System.out.println("代理对象处理请求之后的操作");
  11.     }
  12. }
复制代码
最后,可以通过以下方式使用代理对象:
  1. public class Main {
  2.     public static void main(String[] args) {
  3.         RealSubject realSubject = new RealSubject();
  4.         ProxySubject proxySubject = new ProxySubject(realSubject);
  5.         proxySubject.request();
  6.     }
  7. }
复制代码
运行上述代码可以得到以下输出:
  1. 代理对象处理请求之前的操作
  2. 真实的对象处理请求
  3. 代理对象处理请求之后的操作
复制代码
在这个示例中,ProxySubject 是代理对象,通过持有一个 RealSubject 对象的引用,来代理真实对象的方法调用。在代理对象的 request() 方法中,可以在真实对象的方法调用前后添加一些额外的操纵,从而实现了静态代理。
2、jDK动态代理的实现

在Java中,动态代理可以使用 java.lang.reflect 包中的 Proxy 类和 InvocationHandler 接口来实现。下面是一个简单的动态代理的示例代码:
起首定义一个接口 Subject,包罗一个方法 request():
  1. public interface Subject {
  2.     void request();
  3. }
复制代码
然后创建一个真实的对象 RealSubject,实现 Subject 接口:
  1. public class RealSubject implements Subject {
  2.     @Override
  3.     public void request() {
  4.         System.out.println("真实的对象处理请求");
  5.     }
  6. }
复制代码
接着创建一个实现 InvocationHandler 接口的代理处理器 ProxyHandler:
  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. public class ProxyHandler implements InvocationHandler {
  4.     private Object target;
  5.     public ProxyHandler(Object target) {
  6.         this.target = target;
  7.     }
  8.     @Override
  9.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  10.         System.out.println("代理对象处理请求之前的操作");
  11.         Object result = method.invoke(target, args);
  12.         System.out.println("代理对象处理请求之后的操作");
  13.         return result;
  14.     }
  15. }
复制代码
最后,可以通过以下方式使用动态代理对象:
  1. import java.lang.reflect.Proxy;
  2. public class Main {
  3.     public static void main(String[] args) {
  4.         RealSubject realSubject = new RealSubject();
  5.         ProxyHandler proxyHandler = new ProxyHandler(realSubject);
  6.         Subject proxySubject = (Subject) Proxy.newProxyInstance(
  7.                 RealSubject.class.getClassLoader(),
  8.                 RealSubject.class.getInterfaces(),
  9.                 proxyHandler);
  10.         proxySubject.request();
  11.     }
  12. }
复制代码
运行上述代码可以得到以下输出:
  1. 代理对象处理请求之前的操作
  2. 真实的对象处理请求
  3. 代理对象处理请求之后的操作
复制代码
在这个示例中,ProxyHandler 是代理处理器,通过实现 InvocationHandler 接口,可以在代理对象的方法调用前后添加一些额外的操纵。在 main() 方法中,使用 Proxy 类的 newProxyInstance() 方法动态创建一个代理对象,并将代理处理器传入。然后通过代理对象调用 request() 方法,现实上是调用了代理处理器的 invoke() 方法,在该方法中可以添加额外的操纵,并通过反射调用真实对象的现实方法。
留意,动态代理要求目的类必须实现一个接口,由于动态代理是基于接口来创建代理对象的。
3、CGLIB动态代理的实现

CGLIB(Code Generation Library)是一个用于生成Java类字节码的开源库,它可以在运行时动态生成一个指定类的子类作为代理类。CGLIB动态代理主要用于代理那些没有实现接口的类。
下面是CGLIB动态代理的一个简单示例:
起首,我们需要引入cglib库的依赖,比方使用Maven:
  1. <dependency>
  2.     <groupId>cglib</groupId>
  3.     <artifactId>cglib</artifactId>
  4.     <version>3.3.0</version>
  5. </dependency>
复制代码
然后,创建一个目的类 UserDao:
  1. public class UserDao {
  2.     public void save() {
  3.         System.out.println("保存用户信息");
  4.     }
  5. }
复制代码
接下来,创建一个代理类 CglibProxy:
  1. import net.sf.cglib.proxy.Enhancer;
  2. import net.sf.cglib.proxy.MethodInterceptor;
  3. import net.sf.cglib.proxy.MethodProxy;
  4. import java.lang.reflect.Method;
  5. public class CglibProxy implements MethodInterceptor {
  6.     private Object target;
  7.     public CglibProxy(Object target) {
  8.         this.target = target;
  9.     }
  10.     public Object getProxy() {
  11.         Enhancer enhancer = new Enhancer();
  12.         enhancer.setSuperclass(target.getClass());
  13.         enhancer.setCallback(this);
  14.         return enhancer.create();
  15.     }
  16.     @Override
  17.     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
  18.         System.out.println("代理前的操作");
  19.         Object result = proxy.invoke(target, args);
  20.         System.out.println("代理后的操作");
  21.         return result;
  22.     }
  23. }
复制代码
最后,我们可以使用代理类来生成代理对象并调用目的类的方法:
  1. public class Main {
  2.     public static void main(String[] args) {
  3.         UserDao userDao = new UserDao();
  4.         CglibProxy cglibProxy = new CglibProxy(userDao);
  5.         UserDao proxy = (UserDao) cglibProxy.getProxy();
  6.         proxy.save();
  7.     }
  8. }
复制代码
运行程序,输出效果为:
  1. 代理前的操作
  2. 保存用户信息
  3. 代理后的操作
复制代码
可以看到,CGLIB动态代理通过创建目的类的子类,实现了对目的类方法的代理,同时在代理前后举行了一些额外的操纵。
三、动态带来和静态代理的区别

动态代理和静态代理都是实现代理模式的方式,它们之间的主要区别在于代理对象的生成时机和方式。
总体来说,动态代理相比静态代理具有更高的灵活性和扩展性,但代理对象的生成过程相对复杂一些。静态代理则相对简单,代理对象的生成在编译时期就已经完成。选择使用哪种代理方式取决于具体的需求和场景。
四、代理模式的应用场景

总的来说,代理模式实用于需要在不改变客户端代码的情况下增加额外功能或控制对对象的访问的场景。它可以提供更加灵活、安全和高效的访问方式。
五、SpringBoot中代理模式的实现

在Spring Boot中,代理模式的实现主要通过Spring框架提供的AOP(面向切面编程)功能实现。Spring AOP基于动态代理技术,可以在运行时生成代理对象,并在代理对象的方法执行前后插入额外的逻辑。
以下是使用Spring Boot实现代理模式的示例代码:
  1. public interface UserService {
  2.     void addUser(String username);
  3.     void deleteUser(String username);
  4. }
复制代码
  1. @Service
  2. public class UserServiceImpl implements UserService {
  3.     @Override
  4.     public void addUser(String username) {
  5.         System.out.println("添加用户:" + username);
  6.     }
  7.    
  8.     @Override
  9.     public void deleteUser(String username) {
  10.         System.out.println("删除用户:" + username);
  11.     }
  12. }
复制代码
  1. @Component
  2. @Aspect
  3. public class LogAspect {
  4.     @Before("execution(* com.example.UserService.*(..))")
  5.     public void beforeMethod(JoinPoint joinPoint){
  6.         String methodName = joinPoint.getSignature().getName();
  7.         System.out.println("调用方法:" + methodName);
  8.     }
  9.   
  10.     @AfterReturning("execution(* com.example.UserService.*(..))")
  11.     public void afterMethod(JoinPoint joinPoint){
  12.         String methodName = joinPoint.getSignature().getName();
  13.         System.out.println("方法调用结束:" + methodName);
  14.     }
  15. }
复制代码
  1. @Configuration
  2. @EnableAspectJAutoProxy
  3. public class AppConfig {
  4.     // 其他配置...
  5. }
复制代码
  1. @RestController
  2. public class UserController {
  3.     @Autowired
  4.     private UserService userService;
  5.    
  6.     @PostMapping("/users")
  7.     public void addUser(@RequestParam String username) {
  8.         userService.addUser(username);
  9.     }
  10.    
  11.     @DeleteMapping("/users/{username}")
  12.     public void deleteUser(@PathVariable String username) {
  13.         userService.deleteUser(username);
  14.     }
  15. }
复制代码
通过以上步骤,可以实现在调用UserService接口的方法前后自动插入日记记载的功能,而不需要显式在每个方法中添加日记代码。这就是使用Spring Boot实现代理模式的方式之一。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4