javascript
Spring4:没有默认构造函数的基于CGLIB的代理类
在Spring中,如果要代理的目標對象的類未實現任何接口,則將創建基于CGLIB的代理。 在Spring 4之前,基于CGLIB的代理類需要默認的構造函數。 這不是CGLIB庫的限制,而是Spring本身。 幸運的是,從Spring 4開始,這不再是問題。 基于CGLIB的代理類不再需要默認的構造函數。 這如何影響您的代碼? 讓我們來看看。
依賴注入的慣用法之一是構造函數注入。 它通常在需要注入的依賴項時使用,并且在啟動對象后不得更改。 在本文中,我不會討論為什么和何時應該使用構造函數依賴項注入。 我假設您在代碼中使用了這個習慣用法,或者您考慮使用它。 如果您有興趣了解更多信息,請參見本文底部的資源部分。
不含豆的施工劑注射
具有以下協作者:
package pl.codeleak.services;import org.springframework.stereotype.Service;@Service public class Collaborator {public String collaborate() {return "Collaborating";} }我們可以通過構造函數輕松注入它:
package pl.codeleak.services;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;@Service public class SomeService {private final Collaborator collaborator;@Autowiredpublic SomeService(Collaborator collaborator) {this.collaborator = collaborator;}public String businessMethod() {return collaborator.collaborate();}}您可能會注意到, Collaborator和Service都沒有接口,但是它們都不是代理候選者。 因此,此代碼將在Spring 3和Spring 4上正常運行:
package pl.codeleak.services;import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import pl.codeleak.Configuration;import static org.assertj.core.api.Assertions.assertThat;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = Configuration.class) public class WiringTests {@Autowiredprivate SomeService someService;@Autowiredprivate Collaborator collaborator;@Testpublic void hasValidDependencies() {assertThat(someService).isNotNull().isExactlyInstanceOf(SomeService.class);assertThat(collaborator).isNotNull().isExactlyInstanceOf(Collaborator.class);assertThat(someService.businessMethod()).isEqualTo("Collaborating");} }代豆施工劑注射
在許多情況下,您的bean需要在運行時用AOP proxy進行修飾,例如,當您想將聲明性事務與@Transactional注釋一起使用時。 為了可視化,我創建了一個方面,將為SomeService所有方法提供建議。 在定義了以下方面之后, SomeService將成為代理的候選者:
package pl.codeleak.aspects;import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component;@Aspect @Component public class DummyAspect {@Before("within(pl.codeleak.services.SomeService)")public void before() {// do nothing}}當我使用Spring 3.2.9重新運行測試時,出現以下異常:
Could not generate CGLIB subclass of class [class pl.codeleak.services.SomeService]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given可以通過為SomeService提供默認的,無參數的構造函數來簡單地解決此問題,但這不是我想要做的-因為我還需要使依賴關系成為非最終的。
另一個解決方案是為SomeService提供接口。 但是,在很多情況下,您不需要創建接口。
更新到Spring 4可以立即解決該問題。 如文檔所述:
基于CGLIB的代理類不再需要默認的構造函數。 通過objenesis庫提供支持,該庫以內聯方式重新打包并作為Spring框架的一部分分發。 通過這種策略,不再為代理實例調用任何構造函數。
我創建的測試將失敗,但可以看到為SomeService創建了CGLIB代理:
java.lang.AssertionError: Expecting:<pl.codeleak.services.SomeService@6a84a97d> to be exactly an instance of:<pl.codeleak.services.SomeService> but was an instance of:<pl.codeleak.services.SomeService$$EnhancerBySpringCGLIB$$55c3343b>從測試中刪除第一個斷言后,它將運行得非常好。
資源資源
- 如果您需要了解有關構造函數依賴注入的更多信息,請查看Petri Kainulainen撰寫的這篇出色文章: http ://www.petrikainulainen.net/software-development/design/why-i-changed-my-mind-about 場注入 。
- Spring4中的核心容器改進: http : //docs.spring.io/spring/docs/current/spring-framework-reference/html/new-in-4.0.html#_core_container_improvements
- 您可能也有興趣閱讀有關Spring的其他文章: Spring 4:帶有Java 8 Date-Time API的@DateTimeFormat和
在Spring MVC應用程序中使用Bean Validation 1.1獲得更好的錯誤消息
翻譯自: https://www.javacodegeeks.com/2014/07/spring-4-cglib-based-proxy-classes-with-no-default-constructor.html
總結
以上是生活随笔為你收集整理的Spring4:没有默认构造函数的基于CGLIB的代理类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JPA 2.1实体图–第2部分:在运行时
- 下一篇: vivox80与vivoX80Pro的区