在 Spring javaconfig 中,如何初始化依赖于 @Service 的 @Bean
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21363079/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In Spring javaconfig, how to initialize a @Bean which depends on a @Service
提问by yglodt
I have converted a Spring 4.0-based project from xml to javaconfig.
我已经将一个基于 Spring 4.0 的项目从 xml 转换为 javaconfig。
On initialization, one of my beans needs to access Hibernate to fetch some config-data from the DB, through a Spring @Service (buildingService). The bean initialization looks like this:
在初始化时,我的一个 bean 需要访问 Hibernate 以通过 Spring @Service ( buildingService)从数据库中获取一些配置数据。bean 初始化如下所示:
@Bean
@DependsOn({ "transactionManager", "webSocketHandler", "buildingService" })
Smarty smarty() {
Smarty bean = new Smarty();
bean.init(); // I also tried @Bean(initMethod = "init") with no difference
return bean;
}
The problem is that in bean.init(), the service is accessed, which fails with a NullPointerException.
问题是在 中bean.init(),服务被访问,但失败并显示NullPointerException.
I added buildingServiceto @DependsOnbut it did not help.
我添加buildingService到@DependsOn但它没有帮助。
Probably the @Service-annotated classes are processed after the @Bean!?
可能@Service在@Bean!?之后处理 -annotated 类。
Can I initialize the @Service-annotated class myself upfront?
我可以@Service自己预先初始化-annotated 类吗?
Edit 1
编辑 1
Thanks so far for all the feedback !
到目前为止,感谢所有反馈!
I need to add some details:
我需要添加一些细节:
buildingService is not a @Bean, it's, well, a @Serviceand looks like this:
buildingService 不是 a @Bean,而是 a @Service,看起来像这样:
@Service("buildingService")
@Transactional
public class BuildingService {
...
public List<Building> getAll() {
final Session session = sessionFactory.getCurrentSession();
final Query query = session.createQuery("from Building order by name");
return query.list();
}
...
}
Smarty is a Spring managed Bean, and initialized in an @Configuration-annotated class which is doing the initialization of the root-context.
Smarty 是 Spring 管理的 Bean,并在一个@Configuration-annotated 类中初始化,该类正在执行根上下文的初始化。
Smarty has a direct dependency on buildingService, like so:
Smarty 直接依赖于 buildingService,如下所示:
@Resource(name = "buildingService")
private BuildingService buildingService;
I tried annotating Smarty.init()with @PostConstructbut this did not change anything.
我尝试注释Smarty.init(),@PostConstruct但这并没有改变任何东西。
Note that the first thing Smarty.init()does is calling buildingService.getAll();
请注意,第一件事Smarty.init()是调用buildingService.getAll();
采纳答案by Sotirios Delimanolis
You're confused about the lifecycle of a bean. Spring has to first create the bean before it can inject anything. In your @Beanmethod, you've created your bean
您对 bean 的生命周期感到困惑。Spring 必须先创建 bean,然后才能注入任何东西。在你的@Bean方法中,你已经创建了你的 bean
Smarty bean = new Smarty();
then immediately called one of its methods
然后立即调用其方法之一
bean.init();
that seems to depend on a field being injected.
这似乎取决于被注入的字段。
There's nothing between those two calls. How do you expect Spring to do anything?
这两个电话之间没有任何内容。你如何期望 Spring 做任何事情?
Instead, you could annotate your init()method with @PostConstruct. Once Spring is done initializing your bean, ie. when your @Beanmethod returns and Spring injects all the object's injection targets, it will invoke the method automatically.
相反,您可以init()使用@PostConstruct. 一旦 Spring 完成初始化您的 bean,即。当您的@Bean方法返回并且 Spring 注入对象的所有注入目标时,它会自动调用该方法。
@DependsOnis not necessary here.
@DependsOn这里没有必要。
回答by MariuszS
@Seviceannotated beans are autodiscovered and initialized via component scanning, to enable this use @ComponentScanon Spring Configuration.
@Sevice带注释的 bean 通过组件扫描自动发现和初始化,以@ComponentScan在 Spring Configuration 上启用此用途。
@ComponentScanConfigures component scanning directives for use with
@Configurationclasses.
@ComponentScan配置组件扫描指令以与
@Configuration类一起使用。
@Beanare used for manual creating beans, without using special annotation like @Serviceor component scanning.
@Bean用于手动创建 bean,不使用特殊的注释,如@Service或组件扫描。
@BeanIndicates that a method produces a bean to be managed by the Spring container. (...) Typically, @Bean methods are declared within @Configuration classes. In this case, bean methods may reference other @Bean methods in the same class by calling them directly.
@Bean指示一个方法产生一个由 Spring 容器管理的 bean。(...) 通常,@Bean 方法是在 @Configuration 类中声明的。在这种情况下,bean 方法可以通过直接调用来引用同一个类中的其他@Bean 方法。
Context configuration
上下文配置
@Autowired
EntityManager entityManager; //needs to access Hibernate
@Bean
Smarty smarty() {
return = new Smarty(entityManager);
}
And your Smartybean
还有你的Smarty豆
public Smarty {
final EntityManager entityManager;
public Smarty(EntityManager entityManager){
this.entityManager = entityManager;
}
}
回答by Pieter
You don't need the @DependsOnannotation as you Smarty bean has (or should have) a direct dependency on BuildingService. See the @DependsOnjavadoc for more info on when to use it.
您不需要@DependsOn注释,因为您的 Smarty bean 具有(或应该具有)对 BuildingService 的直接依赖。有关@DependsOn何时使用它的更多信息,请参阅javadoc。
The following example demonstrates how you can solve your problem:
以下示例演示了如何解决您的问题:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SmartyTest.TestConfig.class)
public class SmartyTest {
@Autowired
Smarty1 smarty1;
@Autowired
Smarty2 smarty2;
@Test
public void testSmarty() throws Exception {
}
@Configuration
static class TestConfig {
@Bean
public BuildingService buildingService() {
return new BuildingService();
}
@Bean
public Smarty1 smarty1(BuildingService buildingService) {
Smarty1 smarty = new Smarty1(buildingService);
smarty.init();
return smarty; // manually inject dependencies & handle initialisation
}
@Bean
public Smarty2 smarty2() {
// injecting the building service & initialising the component is handled by spring
// by using @Autowired & @PostConstruct(-> alternative to @Bean(initMethod="init"))
return new Smarty2();
}
}
static class BuildingService {
public void buildSomething() {
System.out.println("BuildingService: I am building something!");
}
}
static class Smarty1 {
BuildingService buildingService;
Smarty1(BuildingService buildingService) {
this.buildingService = buildingService;
}
public void init() {
System.out.println("Smarty 1: initialising ...");
buildingService.buildSomething();
}
}
static class Smarty2 {
@Autowired
BuildingService buildingService;
@PostConstruct
public void init() {
System.out.println("Smarty 2: initialising ...");
buildingService.buildSomething();
}
}
}

