16

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注釈付きのクラスは@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;

で注釈Smarty.init()を付けてみまし@PostConstructたが、これは何も変わりませんでした。

Smarty.init()最初に行うことは呼び出しであることに注意してくださいbuildingService.getAll();

4

3 に答える 3

19

Bean のライフサイクルについて混乱しています。Spring は、何かを注入する前にまず Bean を作成する必要があります。メソッドで、@BeanBean を作成しました

Smarty bean = new Smarty(); 

次に、すぐにそのメソッドの1つを呼び出しました

bean.init();

それは、注入されるフィールドに依存しているようです。

これら 2 つの呼び出しの間には何もありません。Spring が何かを行うことをどのように期待しますか?

代わりに、init()メソッドに@PostConstruct. Spring が完了したら、Bean の初期化を行います。メソッドが@Bean返され、Spring がオブジェクトのすべての注入ターゲットを注入すると、メソッドが自動的に呼び出されます。

@DependsOnここでは必要ありません。

于 2014-01-26T14:35:44.847 に答える
3

@Seviceアノテーション付き Bean は@ComponentScan、Spring 構成でこの使用を有効にするために、コンポーネント スキャンによって自動検出および初期化されます。

@ComponentScan

@Configurationクラスで使用するコンポーネント スキャン ディレクティブを構成します。

@Bean@Serviceコンポーネントスキャンなどの特別な注釈を使用せずに、Bean を手動で作成するために使用されます。

@Bean

メソッドが、Spring コンテナーによって管理される Bean を生成することを示します。(...) 通常、@Bean メソッドは @Configuration クラス内で宣言されます。この場合、Bean メソッドは、同じクラス内の他の @Bean メソッドを直接呼び出すことによって参照できます。


コンテキスト構成

@Autowired
EntityManager entityManager; //needs to access Hibernate

@Bean
Smarty smarty() {
   return = new Smarty(entityManager);
}

そしてあなたのSmarty

public Smarty {

   final EntityManager entityManager;

   public Smarty(EntityManager entityManager){
      this.entityManager = entityManager;
   }
}
于 2014-01-26T12:42:47.693 に答える
1

@DependsOnSmarty 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();
    }
}
}
于 2014-01-26T17:28:52.030 に答える