在Spring javaconfig中,如何初始化依赖于@Service的@Bean

时间:2014-01-26 12:03:29

标签: java spring hibernate spring-java-config

我已将基于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();

3 个答案:

答案 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();
    }
}
}