java动态代理与常规代理的有用性
我需要一些关于动态代理比常规代理更有用的场景的建议。
我投入了大量精力来学习如何有效地使用动态代理。在这个问题中,先不考虑像 AspectJ 这样的框架基本上可以执行我们尝试使用动态代理实现的所有功能,或者例如可以使用 CGLIB 来解决动态代理的一些缺点。
用例
- 装饰器 - 例如,对方法调用执行日志记录,或缓存复杂操作的返回值
- 维护契约 - 也就是说,确保参数在可接受的范围内并且返回类型符合可接受的值。
- 适配器 - 在某处看到一些聪明的文章描述了它的用处。不过我很少遇到这种设计模式。
其他人是吗?
动态代理的优点
- 装饰器:记录所有方法调用,例如,
public Object invoke(Object target, Method method, Object[] arguments) {
System.out.println("before method " + method.getName());
return method.invoke(obj, args);
}
}
装饰器模式绝对有用,因为它允许对所有代理方法产生副作用(尽管此行为是使用方面的书本示例..)。
- 契约:与常规代理相比,我们不需要实现完整的接口。例如,
public Object invoke(Object target, Method method, Object[] arguments) {
if ("getValues".equals(method.getName()) {
// check or transform parameters and/or return types, e.g.,
return RangeUtils.validateResponse( method.invoke(obj, args) );
}
if ("getVersion".equals(method.getName()) {
// another example with no delegation
return 3;
}
}
另一方面,契约仅带来避免实现完整接口的需要的好处。然而,重构代理方法会默默地使动态代理失效。
结论
所以我在这里看到的是一个真实的用例和一个有问题的用例。你有什么意见?
I need some advice to which scenarios a dynamic proxy would prove more useful than a regular proxy.
I've put alot of effort into learning how to use dynamic proxies effectively. In this question, set aside that frameworks like AspectJ can perform basically everything we try to achieve with dynamic proxies, or that e.g., CGLIB can be used to address some of the shortcomings of dynamic proxies.
Use cases
- Decorators - e.g., perform logging on method invocation, or cache return values of complex operations
- Uphold contract - That is, making sure parameters are within accepted range and return types conform to accepted values.
- Adapter - Saw some clever article somewhere describing how this is useful. I rarely come across this design pattern though.
Are the others?
Dynamic proxy advantages
- Decorator: Log all method invocations, e.g.,
public Object invoke(Object target, Method method, Object[] arguments) {
System.out.println("before method " + method.getName());
return method.invoke(obj, args);
}
}
The decorator pattern is definately useful as it allows side effects to all proxies methods (although this behaviour is a book-example of using aspects ..).
- Contract: In contrast to a regular proxy, we need not implement the full interface. E.g.,
public Object invoke(Object target, Method method, Object[] arguments) {
if ("getValues".equals(method.getName()) {
// check or transform parameters and/or return types, e.g.,
return RangeUtils.validateResponse( method.invoke(obj, args) );
}
if ("getVersion".equals(method.getName()) {
// another example with no delegation
return 3;
}
}
The contract on the other hand only gives the benefit of avoiding the need to implement a complete interface. Then again, refactoring proxied methods would silently invalidate the dynamic proxy.
Conclusion
So what I see here is one real use case, and one questionable use case. What's your opinion?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
除了您所描述的之外,动态代理还有许多潜在用途 -
这些只是除了上面描述的验证和日志记录之外的几个选项。 FWIW,JSR 303,一个 bean 验证规范,在 Hibernate Validator 中有一个 AOP 风格的实现,所以你不需要专门为你的数据对象实现它。 Spring 框架还内置了验证,并且对于此处描述的一些内容与 AspectJ 具有非常好的集成。
There are a number of potential uses for dynamic proxies beyond what you've described -
Those are just a few options in addition to validation and logging like you've described above. FWIW, JSR 303, a bean validation specification, has an AOP-style implementation in Hibernate Validator, so you don't need to implement it for your data objects specifically. Spring framework also has validation built in and has really nice integration with AspectJ for some of the stuff described here.
事实上,AOP 对大多数动态代理都有好处。这是因为您可以围绕您事先不知道的对象创建动态代理。
动态代理的另一个有用的方面是当您想要对所有方法应用相同的操作时。使用静态代理,您需要大量重复的代码(在每个代理方法上,您需要对方法进行相同的调用,然后委托给代理对象),而动态代理可以最大限度地减少这种情况。
另请注意,适配器和装饰器是单独的模式。它们在实现方式上看起来像代理模式(通过对象组合),但它们有不同的目的:
EnumetationIterator
- 它将Enumeration
改编为Iterator
接口。Indeed AOP benefits most of the dynamic proxies. That's because you can create a dynamic proxy around an object that you don't know in advance.
Another useful side of a dynamic proxy is when you want to apply the same operation to all methods. With a static proxy you'd need a lot of duplicated code (on each proxied method you would need the same call to a method, and then delegate to the proxied object), and a dynamic proxy would minimize this.
Also note that Adapter and Decorator are separate patterns. They look like the Proxy pattern in the way they are implemented (by object composition), but they serve a different purpose:
EnumetationIterator
- it adapts anEnumeration
to theIterator
interface.我能想到的另一个用例是在运行时动态实现接口,这是某些框架的工作方式。
以 Retrofit 为例,它是一个用于使用 REST 服务的 Java 库。您定义一个反映 REST API 中可用操作的 Java 接口,并使用注释来装饰方法以配置请求的细节。很容易看出,在这种情况下,接口中定义的所有方法都必须对某个服务器执行 HTTP 请求,将方法参数转换为请求参数;然后将响应解析为定义为方法返回类型的 java 对象。
Another use case I can think of is to dynamically implement interfaces at runtime, which is the way some frameworks work.
Take for instance Retrofit, a Java library for consuming REST services. You define a Java interface that reflects the operations available in the REST API, and decorate the methods with annotations to configure specifics of the request. It's easy to see that in this case all methods defined in the interface must execute a HTTP request against some server, transform the method arguments into request parameters; and then parse the response into a java object defined as the method return type.