Sping 源码理解(一)注解驱动

1 组件添加

 

    /**
     * 给容器中注册组件
     * 1》包扫描+组件标注注解(@Controller @Service @Repository @Component [自己写的类])
     * 2》@Bean [导入的第三方包里面的组件]
     * 3》@Import [快速给容器中导入一个组件]
     *    1)@Import(要导入到容器中的组件):容器中就会自动注册这个组件,id默认是全类名
     *    2)ImportSelector:返回需要导入的组件的全类名数组;
     *    3)ImportBeanDefinitionRegistrar: 手动注册bean到容器中
     * 4》使用Spring提供的FactoryBean(工厂bean)
     *       1)默认获取奥的是工厂bean调用getObject创建的对象
     *       2)要获取工厂bean本身,我们需要给id前面加一个&
     *          &colorFactoryBean
     *
     */

    除了 @Controller  @Service  @Repository  @Component基本方式以外;还可以通过 @Configuration   @Bean  @ComponentScan(自动扫描组件TypeFilter过滤)  @ Import 的方式添加组件

 Test.java

    @Test
    public void test01() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : beanDefinitionNames) {
            System.out.println(name);
        }
        Object person = applicationContext.getBean("person");
        Object person1 = applicationContext.getBean("person");
        System.out.println(person == person1);
    }

MainConfig.class

//配置类==配置文件
@Configuration
@ComponentScan(value = "com", includeFilters = {
//        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),   注解类型
//        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class}), //制定类型过滤
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})  //自定义
}, useDefaultFilters = false)//默认过滤开关
//excludeFilters = filter[]
//includeFilters= filter[]  useDefaultFilters = false关闭默认过滤规则,扫描只包含哪些组件
//componentScan value制定要扫描的包
//FilterType.ANNOTATION:按照注解
public class MainConfig {

    //给容器中注册一个bean;类型为返回值的类型,id默认使用方法名作为id
    @Bean
    public Person person() {
        return new Person("lisi", 20);
    }
}

MyTypeFilter.class

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")) {return true;}

        return false;
    }
}

结果:

 

 

 

 

 2 @ Import 添加  @scope 调整作用域

  MainConfig2

//满足当前条件,这个类中配置的所以bean注册才能生效
//@Conditional({LinuxCondition.class})
@Configuration
//导入组件,id默认是组件的全类名
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig2 {
    //默认是单实例的
    //@scope 调整作用域
    //prototype(多实例)  singleton(默认的)ioc启动会调用方法创建对象放到ioc容器中  request(同一次请求创建一个实例)  session(同一个session创建一个实例)

    /**
     * 懒加载:
     *     单实例bean:默认在容器启动的时候创建对象
     *     懒加载:容器启动不加载。第一次使用(获取)bean创建对象,并进行初始化
     * @return
     */
//    @Scope("prototype")
    @Lazy
    @Bean(value = "person")
    public Person person(){
        System.out.println("给容器添加person");
        return new Person("张三", 25);
    }


    /**
     * @conditional({condition}) :按照一定的条件进行判断,满足条件给容器中注册bean
     * 如果是Windows 注册bill
     * 如果是Linux 注入 linas
     */
    @Conditional({WindowsCondition.class})
    @Bean("bill")
    public Person person01() {
        return new Person("Bill Gates", 62);
    }


    @Bean("linas ")
    public Person person02() {
        return new Person("linas", 70);
    }

    /**
     * 给容器中注册组件
     * 1》包扫描+组件标注注解(@Controller @Service @Repository @Component [自己写的类])
     * 2》@Bean [导入的第三方包里面的组件]
     * 3》@Import [快速给容器中导入一个组件]
     *    1)@Import(要导入到容器中的组件):容器中就会自动注册这个组件,id默认是全类名
     *    2)ImportSelector:返回需要导入的组件的全类名数组;
     *    3)ImportBeanDefinitionRegistrar: 手动注册bean到容器中
     * 4》使用Spring提供的FactoryBean(工厂bean)
     *       1)默认获取奥的是工厂bean调用getObject创建的对象
     *       2)要获取工厂bean本身,我们需要给id前面加一个&
     *          &colorFactoryBean
     *
     */
    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }
}


MyImportSelector.class

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

    //返回值,就是到导入到容器中的组件全类名
    //AnnotationMetadata:当前标注@Import注解的类的所有注解信息
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //importClassMetadata
        //
        return new String[]{"com.bean.Blue","com.bean.Yellow"};
    }
}
MyImportBeanDefinitionRegistrar.class
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     *
     * @param importingClassMetadata 当前类的注解信息
     * @param registry BeanDefinition注册类
     *                把所以需要添加到容器中的bean:调用BeanDefinitionRegistry.registerBeanDefinition手工注册进来
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean red = registry.containsBeanDefinition("com.bean.Red");
        if (red) {
            //制定Bean定义信息(Bean的类型,Bean)
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainBow.class);
            //注册一个Bean,指定bean名
            registry.registerBeanDefinition("rainBow", rootBeanDefinition);
        }

    }
}

 

posted @ 2021-10-29 14:16  misr  阅读(42)  评论(0编辑  收藏  举报