-
什么是动态代理
动态代理是Java中一种面向对象编程的技术,允许在运行时创建和使用代理对象,以实现对目标对象的间接访问和控制。它的原理是通过在运行时生成代理类来拦截对目标类的方法调用,并在适当的时候添加额外的逻辑。
-
动态代理实现
在Java中,动态代理主要依赖两个关键接口:InvocationHandler和Proxy。
-
InvocationHandler接口:
定义了代理对象的方法调用处理器。它包含一个invoke()方法,当代理对象的方法被调用时,该方法会被执行。在invoke()方法中,我们可以插入自定义的逻辑,例如记录日志、性能监测等。该接口需要自定义实现。
-
Proxy类:
提供用于创建动态代理类和对象的静态方法。它有两个方法。
- newProxyInstance():用于创建代理对象,接受一个ClassLoader对象、一个Class数组和一个InvocationHandler对象作为参数。它会返回一个实现了目标类接口的代理对象。
- getProxyClass():用于获取代理类的Class对象。
-
-
动态代理的特点:
-
运行时生成:
动态代理不需要事先知道目标对象的类型,而是在运行时生成代理类。
-
透明性:
代理对象与目标对象可以使用相同的接口进行交互,客户端无需关心是否使用了代理。
-
动态性:
可以动态地添加、修改和删除代理行为,而无需修改目标对象的源代码。
-
-
使用场景:
-
AOP(面向切面编程):
动态代理可以在目标对象的方法执行前后插入额外的逻辑,例如日志记录、事务管理等。这样可以将关注点从核心业务逻辑中解耦出来,提高代码可维护性和复用性。
-
代理远程对象:
通过动态代理,可以方便地在网络通信中创建和使用远程服务对象,隐藏底层网络通信的细节,简化开发流程。
-
延迟加载:
动态代理可以延迟加载一些开销较大的对象,只有当真正需要时才去创建和初始化。
-
-
示例
- 下面是一个示例,演示如何使用动态代理实现简单的日志记录功能:
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"); } }
- 当使用动态代理远程对象时,通常会涉及到网络通信和序列化等复杂操作。下面是一个简化的示例,展示如何使用动态代理实现远程调用:
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连接,并将方法名和参数序列化后发送到远程服务器。远程服务器接收到请求后,根据方法名和参数执行相应的方法,并将结果序列化后返回给客户端。客户端接收到结果后打印出来。