はじめに
デフォルトBean名をFQCNにするための方法について解説します。すでに同様の内容を解説したページがいくつかありますが、独自のBeanNameGenerator
実装クラスを定義する内容のものが多く、標準で用意されているBeanNameGenerator
実装クラスを利用する例や複数の設定方法を網羅している解説は無かったため、備忘録として残しておきます。
概要
SpringでアノテーションベースのBean定義を行う場合、特にBean名を明示しない限り、暗黙的にクラス名をLower Camel CaseにしたものがBean名として与えられます。パッケージ名は無視されてしまうので、状況によってはBean名が重複しConflictingBeanDefinitionException
が発生してしまうことがあります。
package com.example.demo.package1
@Service
public class UserService {
/* Bean名:userService */
}
package com.example.demo.package2
@Service
public class UserService {
/* Bean名:userService */
}
クラス名を変更したり、アノテーションにBean名を渡したりすれば回避できますが、クラス数が多いとその管理も面倒になります。
package com.example.demo.package1
@Service("userService1")
public class UserService {
/* Bean名:userService1 */
}
package com.example.demo.package2
@Service("userService2")
public class UserService {
/* Bean名:userService2 */
}
デフォルトで与えられるBean名をパッケージ名まで含めたFQCNにすることで、この問題を回避することができます。
BeanNameGeneratorの指定
Springのコンポーネントスキャン時に使用されるBeanNameGenerator
インターフェースの実装クラスをFullyQualifiedAnnotationBeanNameGenerator
クラスに変更することで、デフォルトで与えられるBean名をFQCNに変更することができます。
BeanNameGenerator
インターフェースは、コンポーネントスキャン時にBean名を自動生成するために使われるインターフェースで、Bean名の生成ロジックはその実装クラスに依存します。デフォルトで使用される実装クラスはAnnotationBeanNameGenerator
クラスです。
コンポーネントスキャン時に使用されるBeanNameGenerator
実装クラスを指定する方法はいくつか存在します。
※FullyQualifiedAnnotationBeanNameGenerator
クラスはSpring Framework 5.2.3 (Spring Boot 2.2.3)
で追加されたため、それ以前のバージョンを使用する場合はこちらの記事等を参考に、独自のBeanNameGenerator
実装クラスを定義して使用してください。
@SpringBootApplication で指定する
SpringBootを使用している場合には、メインクラスに付与する@SpringBootApplication
アノテーションのnameGenerator
パラメータにBeanNameGenerator
実装クラスを指定することで、コンポーネントスキャン時にその実装クラスが使用されるようになります。
@SpringBootApplication(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
public class DemoApplication {
/*...*/
}
@ComponentScan で指定する
SpringBootを使用せず、JavaベースでBean定義を行っている場合は、@ComponentScan
アノテーションのnameGenerator
パラメータにBeanNameGenerator
実装クラスを指定することで、コンポーネントスキャン時にその実装クラスが使用されるようになります。
@Configuration
@ComponentScan(basePackages = "com.example.demo",
nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
public class AppConfig {
/*...*/
}
XMLで指定する
SpringBootを使用せず、XMLベースでBean定義を行っている場合は、<context:component-scan>
タグのnameGenerator
属性にBeanNameGenerator
実装クラスのFQCNを指定することで、コンポーネントスキャン時にその実装クラスが使用されるようになります。
<context:component-scan
base-package="com.example.demo"
name-generator="org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator" />
MyBatis を使用する場合
MyBatisのMapperクラスなどのように、Springのコンポーネントスキャン以外の方法でBean登録されるBeanについては、前述の設定とは別の設定が必要になることがあります。
MyBatisでは、以下の方法でMapperクラスのデフォルトBean名の生成に使用されるBeanNameGenerator
実装クラスを指定することができます。
@MapperScan で指定する
SpringBootを使用している場合や、JavaベースでBean定義を行っている場合は、@MapperScan
アノテーションのnameGenerator
パラメータにBeanNameGenerator
実装クラスを指定することで、マッパースキャン時にその実装クラスが使用されるようになります。
@SpringBootApplication(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
@MapperScan(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
public class DemoApplication {
/*...*/
}
XMLで指定する
SpringBootを使用せず、XMLベースでBean定義を行っている場合は、<mybatis:scan>
タグのnameGenerator
属性にBeanNameGenerator
実装クラスのFQCNを指定することで、マッパースキャン時にその実装クラスが使用されるようになります。
<mybatis:scan
base-package="com.example.demo"
name-generator="org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator" />
参考
- https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/FullyQualifiedAnnotationBeanNameGenerator.html
- https://mybatis.org/spring/ja/mappers.html#Mapper_.E3.81.AE.E8.87.AA.E5.8B.95.E6.A4.9C.E5.87.BA
- https://qiita.com/yu_bookstore/items/07e905cb5b645781bc43
- https://ocs.hatenadiary.org/entry/20101129/1291034951
ご意見・ご指摘等あればコメントいただけると幸いです。