我们最近从一个非常古老的Spring版本(3.2.16.RELEASE
)迁移到了最新版本(4.2.5.RELEASE
)之一。由于这一变化,我们能够在一些.xml
文件中删除超过1k行的代码,并用Java类中的大约50-100个注释替换它们。总而言之,这是一个很大的改变。
昨天我也开始删除@Service
- 注释添加的所有接口。所以,在我们有这样的事情之前:
//The interface:
public interface SomeInterfaceService extends DtoProcessingService<SimpleDto> {
}
//The class:
@Service("someClassService")
public class SomeClassService
extends SomeAbstractClassService<SimpleDto, Strategy>
implements SomeInterfaceService {
...
}
我们已经重构为:
// The interface has been removed
//The class:
@Service
public class SomeClassService
extends SomeAbstractClassService<SimpleDto, Stategy> {
...
}
在新的Spring版本中,@Service
自动使用以小写字母开头的类名(所以someClassService
)。
起初我们收到了一些错误,可能的解决办法是使用Spring xml设置来显式使用代理类。所以,我已经读过一些关于这些代理的力量所暗示的内容,并发现了以下内容:
...根据项目页面&#34; CGLIB用于扩展Java类并在运行时实现接口&#34;。因此,在这种情况下,诀窍在于创建一个 EXTENDS 原始对象的代理,因此可以使用它。 (source)
1)
final
方法无法建议,因为它们无法覆盖。 (source)
2)您将在类路径上需要CGLIB 2二进制文件,而JDK可以使用动态代理。 Spring会在需要CGLIB时自动发出警告,并且在类路径中找不到CGLIB库类。 (source)
3)代理对象的构造函数将被调用两次。这是CGLIB代理模型的自然结果,其中为每个代理对象生成子类。对于每个代理实例,创建两个对象:实际代理对象和实现建议的子类实例。使用JDK代理时不会出现此行为。通常,两次调用代理类型的构造函数不是问题,因为通常只有赋值发生,并且构造函数中没有实现真正的逻辑。 (source)
4)您的课程不能是final
。 (source 1&amp; source 2)
我们的课程都没有final
,他们的方法都没有final
,没有一个类有隐式的构造函数,所以我已将此设置添加到Spring xml中:
<tx:annotation-driven proxy-target-class="true"/>
错误消失了。
现在我有一些问题和疑虑:
有些类/接口有点难以重构,所以我们将它们保留原样(现在)。这些主要是具有大量泛型,抽象的类树,因此难以轻易地重构。此外,还有一些其他类的接口,我甚至还没有触及它仍然使用接口
使用上述设置是否可以同时使用CGLIB
个代理和JDK
接口?
我的猜测并非完全如此。为什么?带接口的类似乎仍然是初始化的,但是以前用Spring / Tapestry自动填充的字段不再适用于这些类(我到处都是NullPointerExceptions
)。例如,以下用于在更改之前正常工作,但geometryMessageService
现在是null
:
// Note that this is an unchanged class
@Transactional
@Service("geometryService")
public class DefaultGeometryService implements GeometryService {
...
private GeometryMessageService geometryMessageService;
public void setGeometryBerichtService(final GeometryBerichtService geometryBerichtService) {
this.geometryBerichtService = geometryBerichtService;
}
public void someMethod(){
...
this.geometryBerichtService.doSomething(); // <- NullPointerException
...
}
}