如何在Component类中注入私有字段,同时在Spring的父类中保持初始化@Autowired ?



我正在学习Spring,同时我喜欢使用@Component和@Autowired让Spring管理依赖bean的想法。例如,我有一个Service类和Builder类,我可以用

// SomeService.java
@Service
public class SomeService {
// SomeBuilder is a @Component class
@Autowired
SomeBuilder someBuilder;
}
// SomeController.java
@Component
public class SomeController {
@Autowired
SomeService someSerivce;
}
Spring将通过使用@Autowired来处理从SomeController到someeservice到SomeBuilder的创建。然而,现在我的SomeService类需要一个私有字段,它不是一个组件类,只是一个普通的上下文对象,例如
// SomeService.java
@Service
public class SomeService {
@Autowired
SomeBuilder someBuilder;

private SomeContext someContext;
// Plan A: Using constructor to initiate the private field. However, I cannot use @Autowired to initiate SomeService in SomeController anymore as it requires a parameterless constructor
// Plan B: using @Autowired on constructor level, I cannot use this because SomeContext is not a @Component class
//public SomeService(SomeContext someContext) {
//this.someContext = someContext;
//}

// Plan C: This seems work but I kinda feel it's not the right way, as usually private field are initiated through constructor
//public void init(SomeContext someContext) {
// this.someContext = someContext;
//}

// demo usage of someContext
public someAnswer realMethod() {
System.out.println(someContext.getName());
}
}

现在我不知道如何注入someecontext现在,我使用

计划A:使用类构造函数

分配私有字段方案B:在构造函数层使用@Autowired

计划C:使用有线方法分配私有域

但我不满意,没有一个明确的方法来做正确的方法。

首先让我们看看你的计划,打破一些神话/误解。

方案A:使用构造函数初始化private字段。然而,我不能使用@AutowiredSomeController中启动SomeService,因为它需要一个无参数构造函数

伟大的计划,这条路要走。@Autowired不依赖于默认构造函数。它只表明您希望用该类型的对象注入字段。该对象如何激活(默认构造函数,带参数的构造函数)对@Autowired无关紧要。所以你的那部分理解是错误的。

在构造函数级别使用@Autowired,我不能使用这个,因为SomeContext不是@Component

如果bean中只有一个构造函数,Spring将自动使用它来满足依赖关系。所以在这种情况下,你不需要@Autowired。bean不必是@Component, bean只是应用程序上下文可用的类的实例。实现这一目标的一种方法是将其标记为@Component,但也有其他方法。就像在一个@Configuration类中定义一个@Bean方法来构造bean一样。

@Configuration
@ComponentScan("your.base.package")
public class YourConfiguration {
@Bean
public SomeContext someContext() {
return new SomeContext();
}
}

类似的东西。它将通过@ComponentScan检测@Component注释类,并将创建一个SomeContext类型的bean作为bean使用。

计划C:这似乎工作,但我有点觉得这不是正确的方式,因为通常private字段是通过构造函数

启动的

您的所有字段都应该是private,而不仅仅是在构造函数中初始化的字段,也包括@Autowired字段。您不希望从外部轻松访问这些字段,以便对其进行修改。所以把它们改成private

话虽如此,还是选择构造函数注入,而不是字段注入或setter/方法注入。它比字段注入更清晰,更少隐藏,也是强制依赖的一种方式(对于可选依赖,你可以使用setter/方法)。

所以使用上面的配置和下面的类,它应该"just work (tm)"。

// SomeService.java
@Service
public class SomeService {
// SomeBuilder is a @Component class  
private final SomeBuilder someBuilder;
private final SomeContext someContext;
public SomeService(SomeBuilder someBuilder, SomeContext someContext) {
this.someBuilder=someBuilder;
this.someContext=someContext;
}
}
// SomeController.java
@Component
public class SomeController {
private final SomeService someSerivce;
public SomeController(SomeService someService) {
this.someService=someService;
}
}

最新更新