java动态代理模式
- Java动态代理模式是Java编程语言中的一种设计模式,它提供了一种在运行时动态创建代理对象的方式。这个模式主要用于实现AOP(面向切面编程)的概念,允许开发者在不修改原有业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理、权限验证等。
在Java中,动态代理模式主要依赖于java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。Proxy类提供了创建代理对象的方法,而InvocationHandler接口定义了代理对象在调用方法时需要实现的接口。 - 动态代理模式的实现步骤如下:
- 定义一个接口,该接口定义了需要被代理的方法,比如:
public interface GreetingService { void greet(String name); }
- 实现该接口的具体业务逻辑类。
public class SimpleGreetingService implements GreetingService{ @Override public void greet(String name) { System.out.println("Hello,"+name+"!"); } }
- 创建一个实现了InvocationHandler接口的类,该类负责处理代理对象的方法调用。在这个类中,可以添加额外的功能,如日志记录、事务管理等。
public class LoggingInvocationhandler implements InvocationHandler { private final Object target; public LoggingInvocationhandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在方法调用前记录日志 System.out.println("Method: "+ method.getName()+ " is called with arguments: "+ Arrays.toString(args)); //调用目标对象的方法 Object result = method.invoke(target, args); //在方法调用后记录日志 System.out.println("Method "+ method.getName()+" is executed"); return result; } }
- 使用Proxy类的静态方法newProxyInstance()创建代理对象。该方法需要三个参数:被代理类的类加载器、被代理类实现的接口数组、实现了InvocationHandler接口的实例。通过代理对象调用方法时,会调用InvocationHandler接口中的invoke()方法。在该方法中,可以添加额外的功能,然后调用被代理对象的方法。
import java.lang.reflect.Proxy; public class DynamicProxyExample { public static void main(String[] args) { //创建目标对象 SimpleGreetingService greetingService = new SimpleGreetingService(); //创建InvocationHandler对象 LoggingInvocationhandler handler = new LoggingInvocationhandler(greetingService); //创建代理对象 GreetingService proxy = (GreetingService) Proxy.newProxyInstance( handler.getClass().getClassLoader(), greetingService.getClass().getInterfaces(), handler); //调用代理对象的方法,实际上会调用InvocationHandler的invoke方法 proxy.greet("World"); } }
动态代理模式的优点是可以在运行时动态创建代理对象,而不需要提前编写代理类的代码。这使得开发者可以更加灵活地实现AOP的概念,提高了代码的可维护性和可扩展性。
- 在Java中,动态代理模式是基于接口的。这意味着你不能直接为一个没有接口的类创建动态代理。动态代理是通过在运行时生成一个新的类来实现的,这个新类实现了你指定的接口,并且将所有方法调用委托给一个InvocationHandler实例。
具体来说,当你使用Proxy.newProxyInstance()方法创建一个代理对象时,你需要提供一个接口数组作为参数之一。这个数组中的接口定义了代理对象需要实现的方法。因此,如果没有接口,动态代理就无法工作。
如果你有一个没有实现任何接口的类,并且想要为它创建代理,那么你不能使用Java标准库中的动态代理模式。在这种情况下,你可能需要使用其他技术或库,如CGLIB。CGLIB是一个强大的高性能的代码生成库,它可以在运行时扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的拦截。
总结一下,"动态代理模式只能用于接口,不能用于类"这句话的意思是:在Java中,你不能直接为没有实现接口的类创建动态代理。如果你需要为一个类创建代理,你可能需要使用其他技术或库,如CGLIB。
补充:案例2
首先,定义一个接口及其实现类:
// 定义一个接口 public interface GreetingService { String sayHello(String name); } // 实现接口的类 public class GreetingServiceImpl implements GreetingService { @Override public String sayHello(String name) { return "Hello, " + name + "!"; } } 接着,创建一个实现了InvocationHandler接口的类,用于处理代理实例上的方法调用并定义横切逻辑(如日志记录、事务管理等): java import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class GreetingServiceProxyHandler implements InvocationHandler { // 目标对象,被代理的对象 private Object target; public GreetingServiceProxyHandler(Object target) { this.target = target; } // 实现invoke方法,处理代理实例上的方法调用 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 可以在这里添加前置通知(如日志记录) System.out.println("Before method " + method.getName() + " is called"); // 调用目标方法 Object result = method.invoke(target, args); // 可以在这里添加后置通知(如日志记录) System.out.println("After method " + method.getName() + " is called"); return result; } // 静态方法,用于创建代理对象 public static Object createProxy(Object target) { // 获取目标对象的类加载器 ClassLoader classLoader = target.getClass().getClassLoader(); // 获取目标对象实现的接口 Class<?>[] interfaces = target.getClass().getInterfaces(); // 创建代理对象 return Proxy.newProxyInstance(classLoader, interfaces, new GreetingServiceProxyHandler(target)); } } 最后,编写客户端代码来测试动态代理: java public class DynamicProxyDemo { public static void main(String[] args) { // 创建目标对象 GreetingService greetingService = new GreetingServiceImpl(); // 创建代理对象 GreetingService proxy = (GreetingService) GreetingServiceProxyHandler.createProxy(greetingService); // 通过代理对象调用方法 String message = proxy.sayHello("Alice"); // 输出结果 System.out.println(message); } }
在这个案例中,GreetingService 接口定义了一个 sayHello 方法,GreetingServiceImpl 类实现了这个方法。GreetingServiceProxyHandler 类实现了 InvocationHandler 接口,并重写了 invoke 方法来定义代理的行为。在 invoke 方法中,我们在调用目标方法前后添加了日志记录。
createProxy 方法是一个静态工厂方法,它使用 Proxy.newProxyInstance 方法来创建代理对象。这个方法需要三个参数:类加载器、接口数组和 InvocationHandler 实例。
在 main 方法中,我们创建了目标对象 greetingService,然后使用 GreetingServiceProxyHandler.createProxy 方法创建了它的代理对象 proxy。最后,我们通过代理对象调用 sayHello 方法,并输出返回的字符串。
运行这个案例,你将看到控制台输出类似以下内容:
Before method sayHello is called
Hello, Alice!
After method sayHello is called
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)