Spring Bootカスタム@Enbale*コメント


Spring Bootカスタム@Enbale*コメント
  • @Enbale*の例@EnbleAsync
  • は、Import Selectorインターフェースを実現することにより、beanのロード
  • を実現する.
  • は、ImportBeanDefinitionRegistarインターフェースを実現することによって、beanのロード
  • を実現する.
  • は、クラスローディングに対するリスニングを実現するためにカスタム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;
    		}
    	}
    
    }
    
    AsyncConfigurationSelectorAdviceModeImportSelectorを継承しているのを見ることができます.私たちがこの父の種類のソースコードを入力すると、AdviceModeImportSelectorImportSelectorというインターフェースを実現し、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