Springアノテーション駆動型開発のコンポーネント登録

SpringBootとSpringCloudが普及したため、Springアノテーション主導の開発の使用が議題になっている必要があります...

まず、Spring構成ファイルの使用を確認します。

①mavenプロジェクトを作成し、春の依存関係をインポートします

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.3.12.RELEASE</version>
</dependency>

②豆のクラスを作成する(人)

public class Person {

    private Integer age;

    private String name;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    public Person(Integer age, String name) {
        this.age = age;
        this.name = name;
    }

    public Person() {
    }
}

③構成ファイルbeans.xmlを書き込み、classpathディレクトリに保存します

<bean class="com.spring.annotation.bean.Person" id="person">
    <property name="age" value="23"></property>
    <property name="name" value="张三"></property>
</bean>

④テストの主な方法を作成する

public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    Person bean = (Person) applicationContext.getBean("person");
    System.out.println(bean);
}

⑤結果は以下のとおりです。

 注釈フォームは、上記の構成ファイルフォームの機能を実装します。構成クラスは構成ファイルと同等です(ただし、形式は異なります)。

@Configuration

①構成クラスMyConfigを作成する

@Configuration//告诉Spring这是一个配置类
public class MyConfig {

    @Bean//给容器中注册一个Bean, 类型是返回值的类型, id默认是用方法名作为id
    public Person person01(){
        return new Person(23, "王五");
    }
}

②主な方法試験

public static void main(String[] args) {
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
    Person bean = applicationContext.getBean(Person.class);
    System.out.println(bean);

    String[] names = applicationContext.getBeanNamesForType(Person.class);
    for (String name: names){
        System.out.println(name);//输出id名称(默认是方法名)
    }
}

③結果は以下のとおりです。

 

④構成クラスMyConfigでID名を指定します

@Configuration//告诉Spring这是一个配置类
public class MyConfig {

    @Bean(name = "person")//给容器中注册一个Bean, 类型是返回值的类型, id默认是用方法名作为id
    public Person person01(){
        return new Person(23, "王五");
    }
}

⑤結果は以下のとおりです。

@ComponentScan

構成ファイルによるパッケージスキャン:@Controller @Service @ Repository @ Componentをスキャンできます

<context:component-scan base-package="com.spring.annotation" use-default-filters="false"/>

注釈付きパッケージスキャン:

①テストクラスIOCTestを作成し、テスト用の新しいController / Service / Daoクラスを作成します

public class IOCTest {

    @Test
    public void test01(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        String[] names = applicationContext.getBeanDefinitionNames();
        for (String name: names){
            System.out.println(name);
        }
    }
}

②構成クラスMyConfigの@ComponentScanアノテーションを使用して、パッケージパスをスキャンします

@Configuration//告诉Spring这是一个配置类
@ComponentScan(value = "com.spring.annotation")
public class MyConfig {

    @Bean(name = "person")//给容器中注册一个Bean, 类型是返回值的类型, id默认是用方法名作为id
    public Person person01(){
        return new Person(23, "王五");
    }
}

③結果は以下のとおりです。

④一部のコンポーネントを除く

@Configuration//告诉Spring这是一个配置类
@ComponentScan(value = "com.spring.annotation", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {
                Controller.class
        })
})
public class MyConfig {

    @Bean(name = "person")//给容器中注册一个Bean, 类型是返回值的类型, id默认是用方法名作为id
    public Person person01(){
        return new Person(23, "王五");
    }
}

⑤特定の成分のみ注入

@Configuration//告诉Spring这是一个配置类
@ComponentScan(value = "com.spring.annotation", includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Service.class})
}, useDefaultFilters = false)
public class MyConfig {

    @Bean(name = "person")//给容器中注册一个Bean, 类型是返回值的类型, id默认是用方法名作为id
    public Person person01(){
        return new Person(23, "王五");
    }
}

⑥jdk8未満のマルチコンポーネントスキャンの使用では、jdk8は複数の@ComponentScanを直接使用できます

@Configuration//告诉Spring这是一个配置类
@ComponentScans(
        value = {
                @ComponentScan(value = "com.spring.annotation", includeFilters = {
                        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Service.class})
                }, useDefaultFilters = false),
                @ComponentScan(value = "com.spring.annotation", excludeFilters = {
                        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
                })
        }
)
public class MyConfig {

    @Bean(name = "person")//给容器中注册一个Bean, 类型是返回值的类型, id默认是用方法名作为id
    public Person person01(){
        return new Person(23, "王五");
    }
}

 ✓FilterTypeの一般的なルール、上記は除外または挿入を行うための注釈タイプに基づいています(FilterType.ANNOTATION)

FilterType.ASSIGNABLE_TYPE:指定されたコンポーネントのタイプに従ってフィルタリングします

@Configuration//告诉Spring这是一个配置类
@ComponentScans(
        value = {
                @ComponentScan(value = "com.spring.annotation", includeFilters = {
                        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Service.class}),
                        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookController.class})
                }, useDefaultFilters = false)
        }
)

結果は次のとおりです。

FilterType.CUSTOM:カスタムルールに従ってフィルタリングします

@Configuration//告诉Spring这是一个配置类
@ComponentScans(
        value = {
                @ComponentScan(value = "com.spring.annotation", includeFilters = {
                        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
                }, useDefaultFilters = false)
        }
)
public class MyConfig {

    @Bean(name = "person")//给容器中注册一个Bean, 类型是返回值的类型, id默认是用方法名作为id
    public Person person01(){
        return new Person(23, "王五");
    }
}

ソースコードによると、TypeFilter実装クラスMyTypeFilterを作成する必要があります

public class MyTypeFilter implements TypeFilter {

    /**
     * @param metadataReader  读取到当前正在扫描的类的信息
     * @param metadataReaderFactory  可以获取到其他任何类的信息
     * @return
     * @throws IOException
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();//获取当前正在扫描的类的注解信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();//获取当前正在扫描的类的信息
        Resource resource = metadataReader.getResource();//获取当前正在扫描的类的资源
        String className = classMetadata.getClassName();
        System.out.println("--->"+className);
        if(className.contains("er")){//如果当前类的类名中包含"er", 则注入
            return true;
        }
        return false;
    }
}

結果は次のとおりです。

 @範囲

スコープは調整可能で、デフォルトのスコープは単一インスタンスです。

@Configuration
public class MyConfig2 {

    @Bean("person")
    public Person person(){
        return new Person(23, "赵六");
    }
}

デフォルトでは単一インスタンス、テスト出力

@Test
public void test02(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
    Person person1 = (Person) applicationContext.getBean("person");
    Person person2 = (Person) applicationContext.getBean("person");
    System.out.println(person1 == person2);
}

結果は次のとおりです。

 マルチインスタンスに変更してテストする

@Configuration
public class MyConfig2 {

    @Scope("prototype")
    @Bean("person")
    public Person person(){
        return new Person(23, "赵六");
    }
}

 結果は次のとおりです。

@レイジー(レイジーローディング)

単一インスタンス:オブジェクトは、コンテナーの開始時に作成され、作成の完了後にコンテナーに保管され、いつでも同じインスタンスになります。

マルチインスタンス:コンテナの起動時にオブジェクトは作成されず、Beanが最初に取得されるまでオブジェクトは作成されません(この時点での状況は遅延ロードです

レイジーローディングのために単一のインスタンスと組み合わせることもできます

@Configuration
public class MyConfig2 {

    @Lazy
    @Bean("person")
    public Person person(){
        return new Person(23, "赵六");
    }
}

@Conditional 

機能:一定の条件で判断し、条件が満たされた場合はコンテナにBeanを登録します。この場合、条件が満たされない場合は、@ Beanアノテーションを追加しても、Beanはコンテナに注入されません。

org.springframework.context.annotationパッケージの下にConditionインターフェイスを実装する2つの判断クラスを作成します

WindowsCondition

//判断是否为windows系统
public class WindowsCondition implements Condition {

    /**
     * @param conditionContext  判断条件能使用的上下文环境
     * @param annotatedTypeMetadata  注释信息
     * @return
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {

        /**
         * todo 判断是否Windows系统
         */
        //获取到ioc当前使用的beanFactory(用于创建对象和装配的)
        ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
        //获取类加载器
        ClassLoader classLoader = conditionContext.getClassLoader();
        //获取环境信息
        Environment environment = conditionContext.getEnvironment();
        //获取到bean定义的注册类
        BeanDefinitionRegistry registry = conditionContext.getRegistry();
        String osName = environment.getProperty("os.name");
        if(osName.contains("Windows")){
            return true;
        }
        return false;
    }
}

LinuxCondition

//判断是否为linux系统
public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {

        Environment environment = conditionContext.getEnvironment();
        String osName = environment.getProperty("os.name");
        if(osName.contains("Linux")){
            return true;
        }
        return false;
    }
}

 @Conditionalアノテーションをテストします

@Conditional({WindowsCondition.class})
@Bean("this is a windows system")
public Person person02(){
    return new Person(23, "田七");
}

@Conditional({LinuxCondition.class})
@Bean("this is a linux system")
public Person person03(){
    return new Person(23, "周八");
}

結果は次のとおりです。

 @インポート 

役割:コンポーネントをコンテナにすばやくインポートすると、コンテナは自動的にコンポーネントを登録します。IDはデフォルトで完全なクラス名です。

使用法①(直接@Import)

新しいBean、Colorクラスを作成します

public class Color {
}
@Configuration
@Import({Color.class})
@Conditional({WindowsCondition.class})
public class MyConfig2 {...}

テスト

@Test
public void testImport(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
    printBean(applicationContext);
}

private void printBean(ApplicationContext applicationContext){
    String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
    for(String beanName: beanDefinitionNames){
        System.out.println(beanName);
    }
}

結果は次のようになります。注入されたBeanのIDは、デフォルトで完全なクラス名になります。

 

 使用法②(特にソースコードで最もよく使用されます)

ImportSelectorインターフェイスを実装する実装クラスMyImportSelectorを作成し、インポートする必要のある完全なクラス名の配列を返します

//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {

    /**
     * @param annotationMetadata  当前标注@Import注解的类的其他注解的所有信息
     * @return
     */
    //返回值就是要导入到容器中的组件的全类名
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"com.spring.annotation.bean.Green", "com.spring.annotation.bean.Yellow"};
    }
}

@ImportアノテーションでMyImportSelectorのクラスオブジェクトを導入します

@Configuration
@Import({Color.class, MyImportSelector.class})
@Conditional({WindowsCondition.class})
public class MyConfig2 {...}

 試験結果は以下のとおりです。

使い方③ 

ImportBeanDefinitionRegistrarインターフェイスを実装してBeanをコンテナに手動で登録する実装クラスMyImportBeanDefinitionRegistrarを作成します

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * @param importingClassMetadata  当前类的注解信息
     * @param registry  bean定义的注册信息
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean green = registry.containsBeanDefinition("com.spring.annotation.bean.Green");
        if(green){
            //指定bean的定义信息(bean的类型, bean的scope...)
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainBow.class);
            //注册一个bean, 指定bean名为rainBow
            registry.registerBeanDefinition("rainBow", rootBeanDefinition);
        }
    }
}

@ImportアノテーションでMyImportBeanDefinitionRegistrarのクラスオブジェクトを導入します

@Configuration
@Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
@Conditional({WindowsCondition.class})
public class MyConfig2 {...}

 試験結果は以下のとおりです。

ファクトリービーン(FactoryBean) 

FactoryBean <Color>を実装する実装クラスColorFactoryBeanを作成します

public class ColorFactoryBean implements FactoryBean<Color> {

    /**
     * 工厂bean通过调用该方法而获取Color的bean对象
     * @return
     * @throws Exception
     */
    @Override
    public Color getObject() throws Exception {
        System.out.println("获取对象bean的方法被调用...");
        return new Color();
    }

    /**
     * 获取Color的类对象
     * @return
     */
    @Override
    public Class<?> getObjectType() {
        return Color.class;
    }

    /**
     * 判断是否是单实例
     * true: 单实例
     * false: 多实例(默认)
     * @return
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

ColorFactoryBeanを構成クラスに登録します

@Bean
public ColorFactoryBean colorFactoryBean(){
    return new ColorFactoryBean();
}

 テスト

@Test
public void testFactoryBean(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
    Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
    Object colorFactoryBean1 = applicationContext.getBean("colorFactoryBean");
    System.out.println(colorFactoryBean.getClass());  //此时的类型是Color
    System.out.println(colorFactoryBean == colorFactoryBean1);  //此时是单例模式, 所以输出true
}

結果は次のとおりです。

戻り値をfalseに変更した場合

@Override
public boolean isSingleton() {
    return false;
}

 試験結果

上記のデフォルトでは、getObject()メソッドを呼び出してファクトリBeanによって作成されたオブジェクトを取得します。ファクトリBean自体のオブジェクトを取得する場合は、コンテナがIDに基づいてBeanを取得するときに、「&」を追加する必要があります。

@Test
    public void testFactoryBean(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
        Object colorFactoryBean = applicationContext.getBean("&colorFactoryBean");
        System.out.println(colorFactoryBean.getClass());  //此时输出是工厂bean本身的对象
    }

結果は次のとおりです。

 理由はソースコードで説明されています

一晩中終了した後、部品登録部分が終了し、次にライフサイクル部分を記述します...

おすすめ

転載: blog.csdn.net/ip_JL/article/details/85399537