4

@Bean を使用してクラスを宣言し、そのクラスのコンポーネント スキャンを行うと、Spring はそのコンストラクターを呼び出し、コンストラクター引数を注入し、@Inject でマークされたフィールドを注入することにより、クラスをインスタンス化します。簡単にするために、このスプリングを auto building と呼びましょう。

私はコンポーネント スキャンが嫌いで、完全に避けたいと思っています (嫌いな理由については話したくありません)。代わりに @Configuration オブジェクトを使用したいのですが、自動ビルド機能を利用できるようにしたいと考えています。@Configuration オブジェクトですべてのコンストラクター引数を明示的に渡す代わりに、Spring を呼び出してオブジェクトを自動ビルドすることは可能ですか?

私が豆を持っていると仮定しましょう:

public class MyServiceImpl implements MyService {
    public MyServiceImpl(Dependency1 d1, Dependency d2) { ... }
    ....
}

次のような構成オブジェクトを定義できます。

@Configuration
public class MyConfiguration {
    // lets assume d1 and d2 are defined in another @Configuration
    @Inject
    Dependency1 d1; 

    @Inject
    Dependency2 d2;

    @Bean
    public MyService myService() { 
        // I dislike how I have to explicitly call the constructor here
        return new MyServiceImpl(d1, d2);
    }
}

しかし今では、MyServiceImpl コンストラクターを自分で明示的に呼び出す必要があったため、コンストラクターが時間の経過とともに変化するにつれて、これを更新し続ける必要があります。

春の自動構築が行われるように、抽象メソッドを宣言できることを望んでいました。

@Configuration
public abstract class MyConfiguration {
    @Bean
    public abstract MyServiceImpl myService();
}

しかし、これはうまくいきません。コンポーネント スキャンを使用せずに春の自動構築を呼び出す方法はありますか?

Google Guice では、これはバインダー経由で行うことができます: https://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/Binder.html

Tapestry IOC では、これは ServiceBinder を介して実行できます: http://tapestry.apache.org/ioc-cookbook-basic-services-and-injection.html#IoCCookbook-BasicServicesandInjection-SimpleServices

アップデート

spodの答えに基づいて、私は自分が求めていたものを達成することができました(ありがとう!)。同じことをしたい人のために含まれているテストケース:

import java.util.Date;
import javax.inject.Inject;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

public class AutoBuildConfigurationTest {
    @Configuration
    public static class MyConfiguration {
        @Inject
        private AutowireCapableBeanFactory beanFactory;

        @Bean
        public Date date() {
            return new Date(12345);
        }

        @Bean
        public MyService myService() {
            return autoBuild(MyService.class);
        }

        protected <T> T autoBuild(Class<T> type) {
            return type.cast(beanFactory.createBean(type, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true));
        }
    }

    public static class MyService {
        private Date date;

        public MyService(Date date) {
            this.date = date;
        }

        public Date getDate() {
            return date;
        }
    }

    @Test
    public void testAutoBuild() {
        ApplicationContext appContext = new AnnotationConfigApplicationContext(MyConfiguration.class);
        MyService myService = appContext.getBean(MyService.class);
        Assert.assertEquals(12345, myService.getDate().getTime());
    }
}
4

1 に答える 1

7

The java based container configuration doesnt depend on doing a component scan in any way. Its merely a different approach for the XML based component configuration. With the XML configuration you'd just have to declare your bean with the MyServiceImpl class in case its already @inject annotated. Spring would recognize the annotations and take care of them. If you really want to instanciate MyServiceImpl from a @Configuration java class without calling the constructor yourself, then you'd have to make use of the bean factory (havent tested it, just give it a try):

@Configuration
public class MyConfiguration {

    @Autowired AutowireCapableBeanFactory beanFactory;

    @Bean public MyService myService() { 
        return beanFactory.createBean(MyServiceImpl.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true);
    }
}
于 2012-11-27T12:30:05.410 に答える