我已将基于Spring 4.0的项目从xml转换为javaconfig。
在初始化时,我的一个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;
}
问题是在bean.init()
中,访问了服务,该服务因NullPointerException
而失败。
我将buildingService
添加到@DependsOn
,但没有帮助。
@Service
之后可能会处理@Bean
- 带注释的类!?
我可以预先自己初始化@Service
- 带注释的课程吗?
修改1
感谢所有反馈!
我需要添加一些细节:
buildingService不是@Bean
,它是@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是一个Spring托管Bean,并在@Configuration
- 带注释的类中进行初始化,该类正在对根上下文进行初始化。
Smarty直接依赖于buildingService,如下所示:
@Resource(name = "buildingService")
private BuildingService buildingService;
我尝试使用Smarty.init()
注释@PostConstruct
,但这并未改变任何内容。
请注意,Smarty.init()
做的第一件事就是调用buildingService.getAll();
答案 0 :(得分:19)
你对bean的生命周期感到困惑。 Spring必须首先创建bean才能注入任何东西。在您的@Bean
方法中,您已经创建了bean
Smarty bean = new Smarty();
然后立即调用其中一个方法
bean.init();
这似乎取决于注入的字段。
这两个电话之间没有任何内容。你怎么期望Spring做任何事情?
相反,您可以使用init()
为@PostConstruct
方法添加注释。一旦Spring完成初始化你的bean,即。当你的@Bean
方法返回并且Spring注入所有对象的注入目标时,它将自动调用该方法。
@DependsOn
在这里没有必要。
答案 1 :(得分:3)
@Sevice
带注释的bean通过组件扫描自动发现并初始化,以便在Spring配置上使用@ComponentScan
。
<强>
@ComponentScan
强>配置组件扫描指令以用于
@Configuration
类。
@Bean
用于手动创建bean,而不使用@Service
或组件扫描等特殊注释。
<强>
@Bean
强>表示方法生成一个由Spring容器管理的bean。 (......) 通常,@ Node方法在@Configuration类中声明。在这种情况下,bean方法可以通过直接调用 来引用同一个类中的其他@Bean方法。
上下文配置
@Autowired
EntityManager entityManager; //needs to access Hibernate
@Bean
Smarty smarty() {
return = new Smarty(entityManager);
}
你的Smarty
bean
public Smarty {
final EntityManager entityManager;
public Smarty(EntityManager entityManager){
this.entityManager = entityManager;
}
}
答案 2 :(得分:1)
您不需要@DependsOn
注释,因为Smarty bean已经(或应该)直接依赖于BuildingService。有关何时使用它的详细信息,请参阅@DependsOn
javadoc。
以下示例演示了如何解决问题:
@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();
}
}
}