动态代理


  1. 什么是动态代理

    动态代理是Java中一种面向对象编程的技术,允许在运行时创建和使用代理对象,以实现对目标对象的间接访问和控制。它的原理是通过在运行时生成代理类来拦截对目标类的方法调用,并在适当的时候添加额外的逻辑。

  2. 动态代理实现

    在Java中,动态代理主要依赖两个关键接口:InvocationHandler和Proxy。

    1. InvocationHandler接口:
      定义了代理对象的方法调用处理器。它包含一个invoke()方法,当代理对象的方法被调用时,该方法会被执行。在invoke()方法中,我们可以插入自定义的逻辑,例如记录日志、性能监测等。该接口需要自定义实现。
    2. Proxy类:
      提供用于创建动态代理类和对象的静态方法。它有两个方法:
      • **newProxyInstance()**:
        用于创建代理对象,接受一个ClassLoader对象、一个Class数组和一个InvocationHandler对象作为参数。它会返回一个实现了目标类接口的代理对象。
      • **getProxyClass()**:
        用于获取代理类的Class对象。
  3. 动态代理的特点:

    • 运行时生成:
      动态代理不需要事先知道目标对象的类型,而是在运行时生成代理类。
    • 透明性:
      代理对象与目标对象可以使用相同的接口进行交互,客户端无需关心是否使用了代理。
    • 动态性:
      可以动态地添加、修改和删除代理行为,而无需修改目标对象的源代码。
  4. 使用场景:

    • AOP(面向切面编程):
      动态代理可以在目标对象的方法执行前后插入额外的逻辑,例如日志记录、事务管理等。这样可以将关注点从核心业务逻辑中解耦出来,提高代码可维护性和复用性。
    • 代理远程对象:
      通过动态代理,可以方便地在网络通信中创建和使用远程服务对象,隐藏底层网络通信的细节,简化开发流程。
    • 延迟加载:
      动态代理可以延迟加载一些开销较大的对象,只有当真正需要时才去创建和初始化。
  5. 示例

    1. 下面是一个示例,演示如何使用动态代理实现简单的日志记录功能:

       import java.lang.reflect.InvocationHandler;
       import java.lang.reflect.Method;
       import java.lang.reflect.Proxy;
       
       interface UserService {
           void addUser(String username);
       }
       
       class UserServiceImpl implements UserService {
           public void addUser(String username) {
               System.out.println("Adding user: " + username);
           }
       }
       
       class LogInvocationHandler implements InvocationHandler {
           private Object target;
       
           public LogInvocationHandler(Object target) {
               this.target = target;
           }
       
           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
               System.out.println("Method " + method.getName() + " called");
               Object result = method.invoke(target, args);
               System.out.println("Method " + method.getName() + " finished");
               return result;
           }
       }
      
       public class DynamicProxyExample {
           public static void main(String[] args) {
               UserService userService = new UserServiceImpl();
               LogInvocationHandler handler = new LogInvocationHandler(userService);
       
               UserService proxy = (UserService) Proxy.newProxyInstance(
                       UserService.class.getClassLoader(),
                       new Class[]{UserService.class},
                       handler
               );
       
               proxy.addUser("John Doe");
           }
       }
       
      
    2. 当使用动态代理远程对象时,通常会涉及到网络通信和序列化等复杂操作。下面是一个简化的示例,展示如何使用动态代理实现远程调用:

       import java.io.*;
       import java.lang.reflect.InvocationHandler;
       import java.lang.reflect.Method;
       import java.lang.reflect.Proxy;
       import java.net.Socket;
       
       interface RemoteService {
           String getData();
       }
       
       class RemoteServiceImpl implements RemoteService {
           public String getData() {
               return "Remote data";
           }
       }
       
       class RemoteInvocationHandler implements InvocationHandler {
           private String host;
           private int port;
       
           public RemoteInvocationHandler(String host, int port) {
               this.host = host;
               this.port = port;
           }
       
           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
               Socket socket = new Socket(host, port);
       
               try {
                   ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
                   ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
       
                   outputStream.writeObject(method.getName());  // 发送方法名
                   outputStream.writeObject(args);  // 发送方法参数
       
                   String result = (String) inputStream.readObject();  // 接收返回结果
                   return result;
               } finally {
                   socket.close();
               }
           }
       }
       
       public class DynamicProxyRemoteExample {
           public static void main(String[] args) {
               String host = "127.0.0.1";
               int port = 8888;
       
               RemoteInvocationHandler handler = new RemoteInvocationHandler(host, port);
       
               RemoteService proxy = (RemoteService) Proxy.newProxyInstance(
                       RemoteService.class.getClassLoader(),
                       new Class[]{RemoteService.class},
                       handler
               );
       
               String remoteData = proxy.getData();
               System.out.println("Remote data: " + remoteData);
           }
       }
      

      在上述示例中,我们定义了一个RemoteService接口及其实现类RemoteServiceImpl。然后创建了一个RemoteInvocationHandler来处理远程调用,并指定远程服务的主机和端口。
      通过使用Proxy.newProxyInstance()方法,我们创建了一个代理对象proxy,它会在调用方法时触发RemoteInvocationHandler的invoke()方法。在invoke()方法中,我们建立了一个Socket连接,并将方法名和参数序列化后发送到远程服务器。
      远程服务器接收到请求后,根据方法名和参数执行相应的方法,并将结果序列化后返回给客户端。客户端接收到结果后打印出来。


嘿手大叔 2024年1月17日 15:25 收藏文档