[英]Too many constructor arguments in Spring Beans
在我的代碼中有一個Bean Admin 。 Admin的一個操作是創建Task並開始它們。
Task執行的操作相當復雜。 因此它被分成幾個不同的Step類。
這就是我的代碼看起來的樣子
public interface Admin{
void start();
//other methods
}
public class AdminImpl implements Admin{
private BeanA bean1;
private BeanB bean2;
//other fields
public Admin(BeanA bean1,
BeanB bean2,
BeanC bean3
//Lot more parameters
BeanO bean15
){
this.bean1 = bean1;
this.bean2 = bean2;
//and so on
}
public void start(){
return new Task(bean1, bean2, bean3,...).start()
}
//other methods
}
public class Task{
private BeanA bean1;
private BeanB bean2;
//other fields
public Task(BeanA bean1,
BeanB bean2,
BeanC bean3
//Lot more parameters
){
//bind parameters to fields
}
public void start(){
new Step1(bean1, bean2,.. other parameters).do();
new Step2(bean3, bean7,.. other parameters).do();
//more steps
}
}
@Configuration
public class MyConfiguration{
@Bean
public Admin admin(BeanA bean1, BeanB bean2....){
return new AdminImpl(bean1, bean2...);
}
}
正如您所看到的,每個Step類都有2個或3個Bean依賴項。 步驟類不是Spring Beans,因此它們是來自Task的依賴項。 任務也不是Spring Bean,因此它從Admin獲取依賴關系。 這導致Admin有太多的依賴關系(~15)。
我試過這個: https : //dzone.com/articles/autowiring-spring-beans-into-classes-not-managed-by-spring 。
基本上,您創建一個名為BeanUtil的服務Bean,它是ApplicationContextAware。 靜態方法getBean使用ApplicationContext獲取bean。
步驟類現在看起來像這樣:
class Step{
public Step(){
BeanA bean1 = BeanUtil.getBean(BeanA.class);
BeanB bean2 = BeanUtil.getBean(BeanB.class);
}
public void do(){
//do stuff
}
}
這解決了最初的問題,但后來我在測試時遇到了困難。 這就是測試類現在的樣子。
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class Step1Test extends AbstractTestNGSpringContextTests {
@Test
public void test(){
Step1 step = new Step().do();
}
@Configuration
static class MockConfiguration {
@Bean
public BeanA beanA() {
BeanA mockBeanA=Mockito.mock(BeanA.class);
// set behavior of mock
return mockBeanA;
}
@Bean
public BeanUtil beanUtil(){
return new BeanUtil();
}
}
}
如果不創建不同的配置類,則無法更改不同測試用例的模擬行為。 這就像通過創建另一個問題來解決一個問題。
這是Spring開發人員面臨的常見問題,其中抽象級別較高的類最終會產生太多依賴關系嗎? 或者我的設計有問題嗎? 處理或避免這種情況的正確方法是什么?
其他似乎相似但沒有的問題
編輯:我從user7得到的一個建議是我將BeanX分組並將抽象傳遞給Admin。 bean沒有任何我可以利用的邏輯分組。 此外,許多步驟需要對bean進行完全訪問(訪問界面中的所有方法)。 這會導致抽象變得臃腫。
您可以將Spring bean作為原型bean(因為它們是有狀態的,並且每次都需要一個不同的實例),並在Task bean中注入Provider<Step>
(如果我理解的話,可以是單例bean)。
例如:
public class Step1 {
private Bean1 bean1;
private Bean2 bean2;
private final String someValue;
private final String someOtherValue;
public Step(String someValue, String someOtherValue) {
this.someValue = someValue;
this.someOtherValue = someOtherValue;
}
@Autowired
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
@Autowired
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
do() {
// ...
}
}
在配置類中,然后將各種步驟定義為bean,方法需要所需的參數:
@Bean
@Scope("prototype")
public Step1 step1(String someValue, String someOtherValue) {
return new Step(someValue, someOtherValue);
}
在Task bean中,您注入了一個ObjectProvider<Step1>
:
private ObjectProvider<Step1> stepProvider;
public Service(ObjectProvider<Step1> step1Provider) {
this.stepProvider = stepProvider;
}
public void start() {
Step1 step1 = step1Provider.getObject("a", "b");
step1.do();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.