1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Spring ContainerにSpring Beanを自動で登録する方法(@ComponentScan, @Component, @Autowired)

Last updated at Posted at 2023-11-12
  • 以前のような@Beanを使う手動登録ではなく、自動Bean登録を行う。

    以前のコード
    package hello.hellospring;
    
    @Configuration
    public class AppConfig {
    
        @Bean
        public MemberService memberService() {
            return new MemberServiceImpl(memberRepository());
        }
    
        @Bean
        public OrderService orderService() {
            return new OrderServiceImpl(memberRepository(), discountPolicy());
        }
    
        @Bean
        public MemberRepository memberRepository() {
            return new MemoryMemberRepository();
        }
    
        @Bean
        public DiscountPolicy discountPolicy() {
            return new RateDiscountPolicy();
        }
    }
    
  • Spring Beanの基本名はclass名を使うが、一番最初の文字だけ小文字を使う。

使用方法

  1. Spring設定情報ファイルの@Configurationに追加で @ComponentScan を付ける。

    • @Configuration:該当クラスがSpring Beanの設定ファイルであることを示す。
    • @ComponentScan:SpringBeanとして登録するクラスを見つける方法を指定する。
    package hello.hellospring;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.FilterType;
    
    @Configuration
    @ComponentScan
    public class AutoAppConfig {
    	// 以前とは異なり、@Beanを別に作成しなくてもよい。
    }
    
  2. classに @Componentを付ける。

    • @Componentが付いたすべてのクラスはSpring Beanに自動的に登録される。
    • @Componentだけでなく、次の内容も追加でComponentScan対象に含める。
      以下のannotationはComponentScan + 付加機能を持っている。
    Annotation 説明
    @Controller Spring MVC Controllerで使用
    @Service Springビジネスロジックで使用、特別な処理をせず、核心ビジネスロジックがここにあることを認識するのに役立つ。
    @Repository   Spring データ アクセス階層で使用、データ階層の例外をSpring例外に変換してくれる。
    @Component // 又は @Repository
    public class MemoryMemberRepository implements MemberRepository{
    	...
    }
    
  3. @Autowiredを付けて依存関係の自動注入を行う。

    • Spring Containerが自動的に該当Spring Beanを探して注入する。
    • 基本照会戦略は同じタイプのBeanを探すことで、以下の場合、ac.getBean(MemberTepository.class)と同一であると理解すればよい。
    @Component // 又は @Service
    public class MemberServiceImpl implements MemberService{
    
        private final MemberRepository memberRepository;
    
        @Autowired
        public MemberServiceImpl(MemberRepository memberRepository){
            this.memberRepository = memberRepository;
        }
    		...
    }
    
    • 依存関係が複数あっても一度に注入してもらえる。
    @Component // 又は @Service
    public class OrderServiceImpl implements OrderService {
    
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;
    
    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
    
    
  4. Annotation Config Application Contextは従来と同様に使用する。

    public class AutoAppConfigTest {
    
        @Test
        void basicScan() {
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);
    
            MemberService memberService = ac.getBean(MemberService.class);
            Assertions.assertThat(memberService).isInstanceOf(MemberService.class);
    
        }
    }
    

重複登録と衝突

Component Scanで同じBeanの名前を登録したら?

  1. 自動Bean登録vs自動Bean登録
    • Springでエラー(Conflicting Bean DefinitionException)を発生させる。
  2. 手動Bean登録vs自動Bean登録
    • 手動Bean登録が優先権を持ち、手動Beanが自動BeanをOverrideして成功に出る。
    • しかし、このような場合は、様々な設定がねじれて作られる場合がほとんどなので、Spring Bootでは衝突したらエラーが発生するように基本値を変えた。

ComponentScanの探索位置

  • 探索するパッケージの開始位置を指定することができる。
  • しかし、パッケージ位置を指定せず、設定情報クラスの位置をプロジェクト最上段に置くことを最もお勧めする。 何も付けないと、@ComponentScanが付いた設定情報classのpackageが開始位置になるからだ。(例のAutoAppConfigの場合、package hello.hellospringである。)
  • Springbootを使えば、SpringBootApplicationにすでに@ComponentScanが基本的に付いているので、どうせBeanが自動的に登録されて@ComponentScan自体を書く必要がなくなる。
  1. basePackages
    • このpackageを含めて下位packageをすべて探索する。
    @ComponentScan(
    	basePackages = "hello.hellospring.member",
    )
    
    // いくつも可能だ。
    @ComponentScan(
    	basePackages = {"hello.hellospring.member", "hello.hellospring.order"}
    )
    
  2. basePackageClasses
    • 指定したclassのpackageを探索開始の上に指定する。
    @ComponentScan(
    	// package hello. hellospring; を探索開始とする。
    	basePackageClasses = AutoAppConfig.class,
    )  
    
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?