Spring Bootカスタム@Enbale*コメント
Spring Bootカスタム@Enbale*コメント@Enbale*の例@EnbleAsync は、Import Selectorインターフェースを実現することにより、beanのロード を実現する.は、ImportBeanDefinitionRegistarインターフェースを実現することによって、beanのロード を実現する.は、クラスローディングに対するリスニングを実現するためにカスタムEnbale注釈をカスタマイズする .
@Enbale*の実例@EnbaleAync
Spring Bootでは、マルチスレッドでコードを実行したい場合、方法の上で注釈
Import Selectorインターフェースを実現することにより、beanのロードを実現します.
一般的に、クラスをロードすることは、簡単な
ImportBenDefinitionRegistarインターフェースを実現することによって、beanのロードを実現します.
同じように、私たちは相変わらずBookクラスを使用して、ロード待ちのクラスとして
ユーザー定義のEnbale注釈により、クラスローディングの傍受を実現します.
@Enbale*の実例@EnbaleAync
Spring Bootでは、マルチスレッドでコードを実行したい場合、方法の上で注釈
@Async
を使用することができますが、同時に、Spring Bootのスタートクラスに@EnableAsync
を配置して注釈@Async
を有効にする必要があります.いったい、@Enable*
はどのような仕事をしていますか?私達は@EnableAsync
のソースコードを見にきました. @Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AsyncConfigurationSelector.class})
public @interface EnableAsync {
注釈の定義では、通常使用されている@Target
、@Retention
、@Documented
のほかに、@Import
の注釈があります.@Import
の中にAsyncConfigurationSelector
の選択器があります.AsyncConfigurationSelector
のソースコードをもう一度見てみます.public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
/**
* Returns {@link ProxyAsyncConfiguration} or {@code AspectJAsyncConfiguration}
* for {@code PROXY} and {@code ASPECTJ} values of {@link EnableAsync#mode()},
* respectively.
*/
@Override
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {ProxyAsyncConfiguration.class.getName()};
case ASPECTJ:
return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
AsyncConfigurationSelector
がAdviceModeImportSelector
を継承しているのを見ることができます.私たちがこの父の種類のソースコードを入力すると、AdviceModeImportSelector
がImportSelector
というインターフェースを実現し、ImportSelector
というインターフェースの中の方法(String[] selectImports(AnnotationMetadata importingClassMetadata);
)は、通常クラスのインスタンス名を返します.つまり、この方法が実現されれば、異なるシーンに応じて、異なるクラスのインスタンスを返すことができる.Import Selectorインターフェースを実現することにより、beanのロードを実現します.
一般的に、クラスをロードすることは、簡単な
@Component
、@Service
、@Controller
などの方法により、クラスを実際的に管理することができますが、@Import
の方法により、クラスの実装を実現することもできます.まず、実用化を待つクラスBook
を定義します.package com.boot.enable.bootenable;
public class Book {
}
Import Selectorインターフェースを実現する実現クラスBeanImportSelector
package com.boot.enable.bootenable;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class BeanImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[] {"com.boot.enable.bootenable.Book"};
}
}
@SpringBootApplication
// Import
@Import(BeanImportSelector.class)
public class BootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(BootEnableApplication.class, args);
System.out.println(context.getBean(Book.class));
}
この時、私たちはBookという種類がすでに実用化されているのを正常に見ることができます.ImportBenDefinitionRegistarインターフェースを実現することによって、beanのロードを実現します.
同じように、私たちは相変わらずBookクラスを使用して、ロード待ちのクラスとして
MyBeanDefinitionRegistrar
クラスを新設し、ImportBeanDefinitionRegistrar
インターフェースを実現します.package com.boot.enable.bootenable;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class MyBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Book.class);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
registry.registerBeanDefinition("book", beanDefinition);
}
}
@SpringBootApplication
// Import
@Import(MyBeanDefinitionRegistrar.class)
public class BootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(BootEnableApplication.class, args);
System.out.println(context.getBean(Book.class));
}
同様に、Bookという種類がすでに実用化されているのが正常に見られます.ユーザー定義のEnbale注釈により、クラスローディングの傍受を実現します.
@Import
はクラスをロードしてくれることが分かりました.次はこの文章のポイントになります.@Enable*
と似たような注釈をどうやって実施して、いくつかのクラスに対するリスニングを実現しますか?まず、@Enable
のクラスが必要です.まず、注釈@EnableScanner
を作成します.package com.boot.enable.bootenable.sample;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(ScannerPackageRegistrar.class)
public @interface EnableScanner {
String[] packages();
}
@EnableScanner
において、@Import
の注釈を使って登録クラスScannerPackageRegistrar
を導入したことが見られます.ScannerPackageRegistrar
を見てみましょう.package com.boot.enable.bootenable.sample;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.util.List;
public class MyBeanDefinitionProcessor implements BeanPostProcessor {
private List<String> packages;
public void setPackages(List<String> packages) {
this.packages = packages;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
for (String pkg : packages) {
if (bean.getClass().getName().contains(pkg)) {
System.out.println("instance bean" + bean.getClass().getName());
}
}
return bean;
}
}
このクラスでは、BeanPostProcessor
インターフェース下のpostProcessBeforeInitialization
方法を実装し、この方法は、インスタンスがロードされる前に、関連するbeanのいくつかの情報を取得するとともに、packagesにおいて、傍受される必要があるファイルのパケット情報を保存してくれる.しかし、私達はこれらだけでは足りません.MyBeanDefinitionProcessorを登録したいです.ImportBeanDefinitionRegistarを実現することによって、私達がカスタマイズしたモニターを登録します.package com.boot.enable.bootenable.sample;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Arrays;
import java.util.List;
public class ScannerPackageRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
String[] attrs = (String[]) importingClassMetadata.getAnnotationAttributes(EnableScanner.class.getName()).get("packages");
List<String> packages = Arrays.asList(attrs);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(MyBeanDefinitionProcessor.class);
builder.addPropertyValue("packages", packages);
registry.registerBeanDefinition(MyBeanDefinitionProcessor.class.getName(), builder.getBeanDefinition());
}
}
私たちはパラメータimportingClass Metadataを通して注釈の関連属性情報を入手できます.同時にもらったpackageを私たちのMyBeanDefinitionProcessorに預けます.このようにして、私たちはクラスローディングの傍受を実現したのと同じです.続いて、私達はテストを行います.テスト中にPerson類を新たに書きました.package com.boot.enable.bootenable.sample.bean;
import org.springframework.stereotype.Component;
@Component
public class Person {
}
現在のPerson類は@ComponentでSpring容器に注解されています.package com.boot.enable.bootenable.sample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
@EnableScanner(packages = {"com.boot.enable.bootenable.sample.bean"})
public class ScannerPackageApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ScannerPackageApplication.class, args);
context.close();
}
}
私たちが運転したらクラスのモニターの結果が得られます.com.boot.enable.bootenable.Book@11a82d0f