spring
豆の作成と使用
サーチ…
特定のタイプのすべてのBeanを自動配線する
同じインターフェースを複数実装している場合、Springはそのすべてをコレクションオブジェクトにオートワイヤリングできます。バリデータパターン1を使用した例を使用します
フークラス:
public class Foo {
private String name;
private String emailAddress;
private String errorMessage;
/** Getters & Setters omitted **/
}
インタフェース:
public interface FooValidator {
public Foo validate(Foo foo);
}
名前バリデータクラス:
@Component(value="FooNameValidator")
public class FooNameValidator implements FooValidator {
@Override
public Foo validate(Foo foo) {
//Validation logic goes here.
}
}
電子メールバリデータークラス:
@Component(value="FooEmailValidator")
public class FooEmailValidator implements FooValidator {
@Override
public Foo validate(Foo foo) {
//Different validation logic goes here.
}
}
これらのバリデータを個別にまたはクラスにまとめてautowireできるようになりました。
インタフェース:
public interface FooService {
public void handleFoo(Foo foo);
}
クラス:
@Service
public class FooServiceImpl implements FooService {
/** Autowire all classes implementing FooValidator interface**/
@Autowired
private List<FooValidator> allValidators;
@Override
public void handleFoo(Foo foo) {
/**You can use all instances from the list**/
for(FooValidator validator : allValidators) {
foo = validator.validate(foo);
}
}
}
Spring IoCコンテナに複数のインタフェースを実装していて、 @Qualifier
アノテーションで@Qualifier
を使用したいのかを指定していない場合、Springは開始しようとすると例外をスローします。なぜなら、どのインスタンスを使用するかはわかりません。
1:これは簡単な検証を行う正しい方法ではありません。これは自動配線に関する簡単な例です。 Springがどのようにアノテーションを使用してバリデーションを行うかを、より容易に検証する方法を考えたい場合。
Beanの宣言
Beanを宣言するために、単にと方法を注釈@Bean
注釈または持つクラスに注釈を付ける@Component
アノテーション(注釈@Service
、 @Repository
、 @Controller
同様に使用することができます)。
JavaConfigがこのようなメソッドに遭遇すると、そのメソッドを実行し、戻り値をBeanFactory内のBeanとして登録します。デフォルトでは、Bean名はメソッド名の名前になります。
Beanは、次の3つの方法のいずれかを使用して作成できます。
Javaベースの設定を使用する :設定ファイルで@beanアノテーションを使用してBeanを宣言する必要があります
@Configuration public class AppConfig { @Bean public TransferService transferService() { return new TransferServiceImpl(); } }
XMLベースの設定を使用する :XMLベースの設定では、アプリケーション設定XMLでdeclare beanを作成する必要があります。
<beans> <bean name="transferService" class="com.acme.TransferServiceImpl"/> </beans>
アノテーション駆動型コンポーネント :アノテーション駆動型コンポーネントでは、Beanとして宣言したいクラスに@Componentアノテーションを追加する必要があります。
@Component("transferService") public class TransferServiceImpl implements TransferService { ... }
transferService
という名前の3つのBeanはすべて、 BeanFactory
またはApplicationContext
使用できApplicationContext
。
基本アノテーションオートワイヤリング
インタフェース:
public interface FooService {
public int doSomething();
}
クラス:
@Service
public class FooServiceImpl implements FooService {
@Override
public int doSomething() {
//Do some stuff here
return 0;
}
}
クラスは、このクラスをautowireできるようにSpringのためのインタフェースを実装する必要があることに注意してください。 Springが読み込み時間を使用してスタンドアロンクラスをオートワイヤリングする方法がありますが、この例では範囲外です。
@Autowired
アノテーションを使用してSpring IoCコンテナによってインスタンス化されたどのクラスでも、このBeanにアクセスできます。
使用法:
@Autowired([required=true])
@Autowired
アノテーションは、最初にタイプ別にオートワイヤリングを試み、あいまいな場合にはBean名に戻ります。
この注釈は、いくつかの異なる方法で適用できます。
コンストラクタインジェクション:
public class BarClass() {
private FooService fooService
@Autowired
public BarClass(FooService fooService) {
this.fooService = fooService;
}
}
フィールドインジェクション:
public class BarClass() {
@Autowired
private FooService fooService;
}
セッター注入:
public class BarClass() {
private FooService fooService;
@Autowired
public void setFooService(FooService fooService) {
this.fooService = fooService;
}
}
動的Beanのインスタンス化のためのFactoryBeanの使用
注入するBeanを動的に決定するために、 FactoryBean
を使用できます。これらは、factoryメソッドパターンを実装するクラスであり、コンテナのBeanのインスタンスを提供します。それらはSpringによって認識され、Beanが工場から来ることを知らずに、透過的に使用することができます。例えば:
public class ExampleFactoryBean extends AbstractFactoryBean<String> {
// This method determines the type of the bean for autowiring purposes
@Override
public Class<?> getObjectType() {
return String.class;
}
// this factory method produces the actual bean
@Override
protected String createInstance() throws Exception {
// The thing you return can be defined dynamically,
// that is read from a file, database, network or just
// simply randomly generated if you wish.
return "Something from factory";
}
}
構成:
@Configuration
public class ExampleConfig {
@Bean
public FactoryBean<String> fromFactory() {
return new ExampleFactoryBean();
}
}
Beanを取得する:
AbstractApplicationContext context = new AnnotationConfigApplicationContext(ExampleConfig.class);
String exampleString = (String) context.getBean("fromFactory");
実際のFactoryBeanを取得するには、Beanの名前の前にアンパサンド接頭辞を使用します。
FactoryBean<String> bean = (FactoryBean<String>) context.getBean("&fromFactory");
prototype
またはsingleton
スコープのみを使用することができます - スコープをprototype
オーバーライドisSingleton
メソッドに変更するには、
public class ExampleFactoryBean extends AbstractFactoryBean<String> {
@Override
public boolean isSingleton() {
return false;
}
// other methods omitted for readability reasons
}
スコープとは、実際に作成されるインスタンスを指し、ファクトリBean自体ではありません。
プロトタイプスコープのBeanをシングルトンに注入する
コンテナはシングルトンBeanを作成し、その中に共同作業者を1回だけ注入します。これは、シングルトンBeanがプロトタイプスコープのコラボレーターを持つ場合、プロトタイプスコープのBeanはアクセサーを介してアクセスされるたびに注入されるため、望ましい動作ではありません。
この問題の解決策はいくつかあります。
- 検索メソッドの注入を使用する
-
javax.inject.Provider
介してプロトタイプスコープのBeanを取得する -
org.springframework.beans.factory.ObjectFactory
を介してプロトタイプスコープのBeanを取得する(#2に相当するが、Spring固有のクラスを持つ) -
ApplicationContextAware
インタフェースを実装してシングルトンBeanコンテナを認識させる
アプローチ#3と#4は、Springフレームワークと強く結びついているので、一般的には推奨されません。したがって、この例では説明しません。
XML設定による抽象メソッドの注入と抽象メソッド
Javaクラス
public class Window {
}
public abstract class WindowGenerator {
public Window generateWindow() {
Window window = createNewWindow(); // new instance for each call
...
}
protected abstract Window createNewWindow(); // lookup method
}
XML
<bean id="window" class="somepackage.Window" scope="prototype" lazy-init="true"/>
<bean id="windowGenerator" class="somepackage.WindowGenerator">
<lookup-method name="createNewWindow" bean="window"/>
</bean>
Javaのコンフィグレーションと@Componentによるメソッドの参照のルックアップ
Javaクラス
public class Window {
}
@Component
public class WindowGenerator {
public Window generateWindow() {
Window window = createNewWindow(); // new instance for each call
...
}
@Lookup
protected Window createNewWindow() {
throw new UnsupportedOperationException();
}
}
Java構成
@Configuration
@ComponentScan("somepackage") // package where WindowGenerator is located
public class MyConfiguration {
@Bean
@Lazy
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Window window() {
return new Window();
}
}
Javaの設定による手動検索メソッドの注入
Javaクラス
public class Window {
}
public abstract class WindowGenerator {
public Window generateWindow() {
Window window = createNewWindow(); // new instance for each call
...
}
protected abstract Window createNewWindow(); // lookup method
}
Java構成
@Configuration
public class MyConfiguration {
@Bean
@Lazy
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Window window() {
return new Window();
}
@Bean
public WindowGenerator windowGenerator(){
return new WindowGenerator() {
@Override
protected Window createNewWindow(){
return window();
}
};
}
}
経由シングルトンにprotoypeスコープのBeanの注入javax.inject.Provider
Javaクラス
public class Window {
}
public class WindowGenerator {
private final Provider<Window> windowProvider;
public WindowGenerator(final Provider<Window> windowProvider) {
this.windowProvider = windowProvider;
}
public Window generateWindow() {
Window window = windowProvider.get(); // new instance for each call
...
}
}
XML
<bean id="window" class="somepackage.Window" scope="prototype" lazy-init="true"/>
<bean id="windowGenerator" class="somepackage.WindowGenerator">
<constructor-arg>
<bean class="org.springframework.beans.factory.config.ProviderCreatingFactoryBean">
<property name="targetBeanName" value="window"/>
</bean>
</constructor-arg>
</bean>
他のスコープに対しても同じ手法を使用できます(たとえば、リクエストスコープのBeanをシングルトンに注入する場合など)。
@Qualifierで特定のBeanインスタンスを自動配線する
同じインターフェースを複数実装している場合、Springはクラスにオートワイヤリングする必要があるかどうかを知る必要があります。この例では、Validatorパターンを使用します。 1
フークラス:
public class Foo {
private String name;
private String emailAddress;
private String errorMessage;
/** Getters & Setters omitted **/
}
インタフェース:
public interface FooValidator {
public Foo validate(Foo foo);
}
名前バリデータクラス:
@Component(value="FooNameValidator")
public class FooNameValidator implements FooValidator {
@Override
public Foo validate(Foo foo) {
//Validation logic goes here.
}
}
電子メールバリデータークラス:
@Component(value="FooEmailValidator")
public class FooEmailValidator implements FooValidator {
@Override
public Foo validate(Foo foo) {
//Different validation logic goes here.
}
}
これらのバリデーターをクラスに個別にautowireできるようになりました。
インタフェース:
public interface FooService {
public void handleFoo(Foo foo);
}
クラス:
@Service
public class FooServiceImpl implements FooService {
/** Autowire validators individually **/
@Autowired
/*
* Notice how the String value here matches the value
* on the @Component annotation? That's how Spring knows which
* instance to autowire.
*/
@Qualifier("FooNameValidator")
private FooValidator nameValidator;
@Autowired
@Qualifier("FooEmailValidator")
private FooValidator emailValidator;
@Override
public void handleFoo(Foo foo) {
/**You can use just one instance if you need**/
foo = nameValidator.validate(foo);
}
}
Spring IoCコンテナに複数のインタフェースを実装していて、 @Qualifier
アノテーションで@Qualifier
を使用したいのかを指定していない場合、Springは開始しようとすると例外をスローします。なぜなら、どのインスタンスを使用するかはわかりません。
1:これは簡単な検証を行う正しい方法ではありません。これは自動配線に関する簡単な例です。 Springがどのようにアノテーションを使用してバリデーションを行うかを、より容易に検証する方法を考えたい場合。
ジェネリック型パラメータを使用してクラスの特定のインスタンスをオートワイヤする
ジェネリック型パラメータを持つインタフェースを持っている場合、Springはそれを使って、指定した型パラメータを実装する実装だけを自動配線します。
インタフェース:
public interface GenericValidator<T> {
public T validate(T object);
}
Fooバリデータークラス:
@Component
public class FooValidator implements GenericValidator<Foo> {
@Override
public Foo validate(Foo foo) {
//Logic here to validate foo objects.
}
}
バーバリデータークラス:
@Component
public class BarValidator implements GenericValidator<Bar> {
@Override
public Bar validate(Bar bar) {
//Bar validation logic here
}
}
タイプパラメータを使用してこれらのバリデータを自動配線して、どのインスタンスを自動配線するかを決定できるようになりました。
インタフェース:
public interface FooService {
public void handleFoo(Foo foo);
}
クラス:
@Service
public class FooServiceImpl implements FooService {
/** Autowire Foo Validator **/
@Autowired
private GenericValidator<Foo> fooValidator;
@Override
public void handleFoo(Foo foo) {
foo = fooValidator.validate(foo);
}
}