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");
          }
      }
    
    1. 当使用动态代理远程对象时,通常会涉及到网络通信和序列化等复杂操作。下面是一个简化的示例,展示如何使用动态代理实现远程调用:
    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连接,并将方法名和参数序列化后发送到远程服务器。远程服务器接收到请求后,根据方法名和参数执行相应的方法,并将结果序列化后返回给客户端。客户端接收到结果后打印出来。