Spring 4.0ベースのプロジェクトをxmlからjavaconfigに変換しました。
初期化時に、Beanの1つがHibernateにアクセスして、Spring @Service(buildingService
)を介してDBからいくつかの構成データをフェッチする必要があります。 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
- annotatedクラスは@Bean
!?の後に処理されます
@Service
- annotatedクラスを自分で初期化できますか?
編集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
- annotatedクラスで初期化されます。
Smartyは、次のようにbuildingServiceに直接依存しています。
@Resource(name = "buildingService")
private BuildingService buildingService;
@PostConstruct
でSmarty.init()
に注釈を付けてみましたが、これは何も変更しませんでした。
Smarty.init()
が最初に行うことは、buildingService.getAll();
を呼び出すことです。
Beanのライフサイクルについて混乱しています。 Springは、何かを注入する前に、まずBeanを作成する必要があります。 _@Bean
_メソッドで、Beanを作成しました
_Smarty bean = new Smarty();
_
その後、すぐにそのメソッドの1つを呼び出しました
_bean.init();
_
注入されるフィールドに依存しているようです。
これらの2つの呼び出しの間には何もありません。 Springに何かを期待しますか?
代わりに、init()
メソッドに_@PostConstruct
_の注釈を付けることができます。 SpringがBeanの初期化を完了すると、つまり_@Bean
_メソッドが戻り、Springがオブジェクトのすべてのインジェクションターゲットをインジェクトすると、メソッドが自動的に呼び出されます。
ここでは_@DependsOn
_は不要です。
@Sevice
注釈付きBeanは、コンポーネントのスキャンを介して自動検出および初期化され、Spring構成で@ComponentScan
を使用できるようにします。
@ComponentScan
@Configuration
クラスで使用するコンポーネントスキャンディレクティブを設定します。
@Bean
は、@Service
やコンポーネントスキャンなどの特別な注釈を使用せずに、Beanを手動で作成するために使用されます。
@Bean
メソッドがSpringコンテナによって管理されるBeanを生成することを示します。 (...)通常、@ Beanメソッドは@Configurationクラス内で宣言されます。この場合、Beanメソッドは、directlyを呼び出すことにより、同じクラス内の他の@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;
}
}
Smarty Beanは、BuildingServiceに直接依存している(または持っている必要がある)ので、@DependsOn
注釈は必要ありません。使用するタイミングの詳細については、 @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();
}
}
}