Spring注解驱动开发04(给容器中注册组件的方式)

给容器中注册组件的三种方式

1. 组件注解标注 + 包扫描(适用于自己写的类)

//控制层组件
@Controller
public class PersonController {
}

//业务逻辑层组件
@Service
public class PersonServic {
}

//持久层组件
@Repository
public class PersonDao {
}

//其他组件
@Component
public class Person {
}

包扫描(注解或者xml的方式)

1.使用注解的方式
@ComponentScan(value = "com.xxx")

2.使用xml的方式
<context:component-scan base-package="com.xxx"/>    

2. @Bean(适用于第三方包里面的组件)

了解@Bean使用详情

@Bean("组件id") 默认使用方法名作为id,返回值作为组件的类型

3. @Import(快速给容器中导入一个组件)

@Import的第一种用法

  1. 直接在配置类上加上注解@Import(要加入到ioc容器中的类的类模板)
@Configuration
@ComponentScan(value = "com.atguigu",excludeFilters = {
        //不扫描@controller和service注解,type默认为注解类型,可以不写
        @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {Myfilter.class})})
@SuppressWarnings("all")
@Import(HashMap.class)  //将HashMap类加入到ioc容器中
public class MainConfig {
}

可以看到@Import注解的value时个数组,所以也可以导入多个值
注意:@Import注入的bean默认id为类的全限定名

public @interface Import {

	/**
	 * {@link Configuration @Configuration}, {@link ImportSelector},
	 * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
	 */
	Class<?>[] value();

}

@Import(HashMap.class,TreeMap.class)  //将HashMap类加入到ioc容器中
public class MainConfig {
}
  1. 编写测试类
    @Test
    public void testImport(){
        try(ConfigurableApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig.class)) {
            //查看容器中的所有对象
            String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
            for (String beanDefinitionName : beanDefinitionNames) {
                System.out.println(beanDefinitionName);
            }
        }
    }
  1. 查看打印结果
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
personController
personServic
java.util.HashMap  //可以看到ioc容器中已经有hashmap
java.util.TreeMap  //可以看到ioc容器中已经有treemap
person
p1

@Import的第二种用法:ImportSelector方式【重点】

这种方式的前提就是一个类要实现ImportSelector接口,假如我要用这种方法,目标对象是Myclass这个类,分析具体如下:

  1. 创建Myclass类并实现ImportSelector接口
//自定义逻辑返回需要导入的组件
public class MyClass implements ImportSelector {

    /**
     * @param importingClassMetadata 表示当前被@Import注解给标注的所有注解信息【不是重点】
     * @return 就是我们实际上要导入到容器中的组件全类名【重点 】
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{
            "java.util.LinkedHashSet",
            "java.util.ArrayList"
        };
    }

}
  1. 在@Import注解上加入属性自定义类
@Import({HashMap.class, TreeMap.class, MyClass.class})
  1. 测试类
    @Test
    public void testImport(){
        try(ConfigurableApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig.class)) {
            System.out.println(ioc);
            //查看容器中的所有对象
            String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
            for (String beanDefinitionName : beanDefinitionNames) {
                System.out.println(beanDefinitionName);
            }
        }
    }
  1. 查看打印结果
    打印结果

@Import的第三种用法:ImportBeanDefinitionRegistrar方式

同样是一个接口,类似于第二种ImportSelector用法,相似度80%,只不过这种用法比较自定义化注册,具体如下:

第一步:创建Myclass2类并实现ImportBeanDefinitionRegistrar接口

public class Myclass2 implements ImportBeanDefinitionRegistrar {
//该实现方法默认为空
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
      
    }
}

参数分析:

  • 第一个参数:annotationMetadata 和之前的ImportSelector参数一样都是表示当前被@Import注解给标注的所有注解信息
  • 第二个参数表示用于注册定义一个bean

第二步:编写代码,自定义注册bean

public class Myclass2 implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        //指定bean定义信息(包括bean的类型、作用域...)
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestDemo4.class);
        //注册一个bean指定bean名字(id)
        beanDefinitionRegistry.registerBeanDefinition("TestDemo4444",rootBeanDefinition);
    }
}

第三步:编写TestDemo 类,并标注上使用ImportBeanDefinitionRegistrar方式的Myclass2类

@Import({TestDemo2.class,Myclass.class,Myclass2.class})
public class TestDemo {

        @Bean
        public AccountDao2 accountDao222(){
            return new AccountDao2();
        }

}

第四步:运行结果

org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
personController
personServic
java.util.HashMap
java.util.TreeMap
java.util.LinkedHashSet
java.util.ArrayList
person
p1
TestDemo4444 //可以看到已经在ioc中

4. @Import注解的三种使用方式总结

第一种用法:@Import({ 要导入的容器中的组件 } ):容器会自动注册这个组件,id默认是全类名

第二种用法:ImportSelector:返回需要导入的组件的全类名数组,springboot底层用的特别多【重点 】

第三种用法:ImportBeanDefinitionRegistrar:手动注册bean到容器

以上三种用法方式皆可混合在一个@Import中使用,特别注意第一种和第二种都是以全类名的方式注册,而第三中可自定义方式。
@Import注解本身在springboot中用的很多,特别是其中的第二种用法ImportSelector方式在springboot中使用的特别多,尤其要掌握!

posted @ 2020-08-19 18:28  _五月雨  阅读(195)  评论(0编辑  收藏  举报
Live2D