当前位置 博文首页 > 是倩倩不是欠欠:Spring组件注册

    是倩倩不是欠欠:Spring组件注册

    作者:是倩倩不是欠欠 时间:2021-02-15 18:28

    Spring组件注册

    @Configuration

    @Configuration注解告诉Spring这是一个配置类

    @Bean

    @Bean注解是给容器中注册一个Bean,类型是返回值的类型,id默认是方法名作为id

        @Bean("person")
        public Person person2(){
            System.out.println("create a new bean of person");
            return new Person();
        }
    

    @ComponentScan

    @ComponentScan(value = "com.eric",excludeFilters = {
    @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})

    @ComponentScan 的属性

    • value:指定要扫描的包
    • excludeFilters = Filter[]:指定扫描的时候按照什么规则排除哪些组件
    • includeFilters = Filter[]:指定扫描的时候只需要包含哪些组件
    /**
     * Description: spring-parent
     * 配置类==配置文件
     *
     * @author caoqianqian
     * @date 2021/2/14
     */
    @Configuration //告诉Spring这是一个配置类
    @ComponentScan(value = "com.eric",excludeFilters = {
    		@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})
    })
    public class MainConfig {
    
    	//给容器中注册一个Bean,类型是返回值的类型,id默认是方法名作为id
    	@Bean
    	public Person person(){
    		return new Person("testName",20);
    	}
    }
    

    @Scope

    通过@Scope注解来制定该bean的作用范围,也可以说是调整作用域,ioc容器中加载的组件默认是单实例的。

    作用域范围即value的可取值范围

    • prototype 多实例的:ioc容器启动并不会去调用方法创建对象放到容器中,每次获取的时候才会调用方法创建对象。
    • singleton 单实例的(默认值):
      ioc容器启动时会调用方法创建对象,放到ioc容器中,以后每次获取就是从容器中(map.get())拿
    • request 同一次请求创建一个实例
    • session 同一个session创建一个实例
    //通过@Scope注解来制定该bean的作用范围,也可以说是调整作用域
            @Scope("singleton")
    	@Bean("person")
    	public Person person() {
    		System.out.println("I'm creating an instance Person");
    		return new Person("Person", 28);
    	}
    

    @Lazy 懒加载

    单实例bean:默认在容器启动的时候创建对象。
    懒加载:容器启动不创建对象,第一次使用(获取)bean时创建对象,并初始化。

    单实例bean加上懒加载的注解之后容器启动时不创建对象,第一次使用时才会去创建对象并初始化。

        @Bean("person")
        @Lazy
        public Person person2(){
            System.out.println("create a new bean of person");
            return new Person();
        }
    

    @Conditional

    @Conditional按照一定的条件进行判断,满足条件给容器中注册bean

    标在方法上,表示这个方法满足一定条件才会生效。

    标在类上,类中组件统一设置,表示满足当前条件,这个类中配置的所有bean注册才会生效

    判断是否是Linux系统

    public class LinuxCondition implements Condition {
    	/**
    	 *判断是否是Linux系统
    	 * @param conditionContext 判断条件能使用的上下文(环境)
    	 * @param annotatedTypeMetadata 当前标注注解的注释信息
    	 * @return
    	 */
    	@Override
    	public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
    		//能获取到ioc使用的beanFactory
    		ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
    		//获取类加载器
    		ClassLoader classLoader = conditionContext.getClassLoader();
    		//获取当前环境信息
    		Environment environment = conditionContext.getEnvironment();
    		//获取bean定义的注册类
    		BeanDefinitionRegistry registry = conditionContext.getRegistry();
    
    		//判断容器中bean的注册情况
    		boolean definition = registry.containsBeanDefinition("person");
    		RootBeanDefinition beanDefinition = new RootBeanDefinition(Person.class);
    		//给容器中注册bean
    		registry.registerBeanDefinition("person2",beanDefinition);
    		String property = environment.getProperty("os.name");
    
    		if(property.contains("linux")){
    			return true;
    		}
    		return false;
    	}
    }
    

    判断是否是Windows系统

    public class WindowsCondition implements Condition {
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            Environment environment = conditionContext.getEnvironment();
            String osName = environment.getProperty("os.name");
            if (osName.contains("Windows")){
                return true;
            }
            return false;
        }
    }
    

    配置类

    @Configuration
    public class MainConfig2 {
        /**
         *Conditional({Condition}):按照一定的条件进行判断,满足条件给容器中注册bean
         * 如果系统是windows,给容器中注册("bill")
         * 如果系统是linux,给容器中注册("linus")
         * @return
         */
        @Conditional({WindowsCondition.class})
        @Bean("bill")
        public Person person(){
            return new Person("Bill Gates",62);
        }
    
        @Conditional({LinuxCondition.class})
        @Bean("linus")
        public Person person2(){
            return new Person("linus",42);
        }
    
        @Bean
        public ColorFactoryBean colorFactoryBean(){
            return new ColorFactoryBean();
        }
    }
    

    测试方法

            @Test
    	public void testCondition() {
    		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig2.class);
    		ConfigurableEnvironment environment = ac.getEnvironment();
    		String[] beanNamesForType = ac.getBeanNamesForType(Person.class);
    		//动态获取环境变量的值:windows 7
    		String property = environment.getProperty("os.name");
    		System.out.println(property);
    		for (String p:beanNamesForType) {
    			System.out.println(p);
    		}
    	}
    

    运行结果如下,Windows 7的系统所以bill注册了进来

    Windows 7
    bill
    person2
    

    @Import

    快速导入组件,id默认是组件的全类名

    配置类上加了@Import注解

    @Configuration
    @Import({Color.class, Dog.class})
    public class MainConfig2 {
        /**
         *Conditional({Condition}):按照一定的条件进行判断,满足条件给容器中注册bean
         * 如果系统是windows,给容器中注册("bill")
         * 如果系统是linux,给容器中注册("linus")
         * @return
         */
        @Conditional({WindowsCondition.class})
        @Bean("bill")
        public Person person(){
            return new Person("Bill Gates",62);
        }
    
        @Conditional({LinuxCondition.class})
        @Bean("linus")
        public Person person2(){
            return new Person("linus",22);
        }
    }
    

    测试方法

            @Test
    	public void testImport() {
    		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig2.class);
    		String[] beanNamesForType = ac.getBeanDefinitionNames();
    		for (String p:beanNamesForType) {
    			System.out.println(p);
    		}
    	}
    

    运行结果:除了内部的bean,Color和Dog也被注册进来了

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    mainConfig2
    com.eric.bean.Color
    com.eric.bean.Dog
    bill
    person2
    

    @Import使用ImportSelector

    //自定义逻辑返回需要导入的组件
    public class MyImportSelector implements ImportSelector {
        //返回值就是导入到容器中的组件的全类名
        //AnnotationMetadata 当前标注@Import注解类的所有注解信息
        @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            Set<String> annotationTypes = annotationMetadata.getAnnotationTypes();
             for(String str : annotationTypes){
                System.out.println("===="+str);
            }
    
            return new String[]{"com.eric.bean.Blue","com.eric.bean.Red"};
        }
    }
    

    @Import注解加上自定义的组件MyImportSelector

    @Configuration
    @Import({Color.class, Dog.class,MyImportSelector.class})
    public class MainConfig2 {
        /**
         *Conditional({Condition}):按照一定的条件进行判断,满足条件给容器中注册bean
         * 如果系统是windows,给容器中注册("bill")
         * 如果系统是linux,给容器中注册("linus")
         * @return
         */
        @Conditional({WindowsCondition.class})
        @Bean("bill")
        public Person person(){
            return new Person("Bill Gates",62);
        }
    
        @Conditional({LinuxCondition.class})
        @Bean("linus")
        public Person person2(){
            return new Person("linus",22);
        }
    
    }
    

    测试方法

            @Test
    	public void testImport() {
    		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig2.class);
    		String[] beanNamesForType = ac.getBeanDefinitionNames();
    		for (String p:beanNamesForType) {
    			System.out.println(p);
    		}
    	}
    

    运行结果:Blue Red 都被注册进来了

    ====org.springframework.context.annotation.Configuration
    ====org.springframework.context.annotation.Import
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    mainConfig2
    com.eric.bean.Color
    com.eric.bean.Dog
    com.eric.bean.Blue
    com.eric.bean.Red
    bill
    person2
    

    @Import使用ImportBeanDefinitionRegistrar

    手动注册bean到容器中

    //要被注册的bean
    public class Rainbow {
    }
    
    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    
        /**
         *
         * @param importingClassMetadata    当前类的注解信息
         * @param registry                  BeanDefinition注册类
         *        把所有需要添加到容器中的bean,调用
         *        BeanDefinitionRegistry.registerBeanDefinition手工注册进来
         */
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            boolean blueDefinition = registry.containsBeanDefinition("com.eric.bean.Blue");
            if (blueDefinition){
                //指定bean的定义信息
                RootBeanDefinition beanDefinition = new RootBeanDefinition(Rainbow.class);
                //注册一个bean,指定bean名
                registry.registerBeanDefinition("rainbow", beanDefinition);
            }
        }
    }
    

    配置类:@Import加入了中MyImportBeanDefinitionRegistrar

    @Configuration
    @Import({Color.class, Blue.class,MyImportBeanDefinitionRegistrar.class})
    public class MainConfig2 {
        
    }
    

    测试方法:

            @Test
    	public void testImport() {
    		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig2.class);
    		String[] beanNamesForType = ac.getBeanDefinitionNames();
    		for (String p:beanNamesForType) {
    			System.out.println(p);
    		}
    	}
    

    运行结果:逻辑判断Blue存在所以rainbow被注册了进来

    mainConfig2
    com.eric.bean.Blue
    bill
    person2
    rainbow
    

    使用FactoryBean注册组件

    使用spring提供的FactoryBean(工厂Bean)

    创建一个ColorFactoryBean实现FactoryBean接口:

    //创建一个Spring定义的FactoryBean
    public class ColorFactoryBean implements FactoryBean<Color> {
    
        /**
         * 返回一个Color对象,这个对象会添加到容器中
         * @return
         * @throws Exception
         */
        @Override
        public Color getObject() throws Exception {
            System.out.println("ColorFactoryBean=========getObject=====");
            return new Color();
        }
    
        /**
         * 返回的bean类型
         * @return
         */
        @Override
        public Class<Color> getObjectType() {
            return Color.class;
        }
    
        /**
         * 是否单例
         * 返回true代表是单实例,在容器中保存一份
         * false是多实例,每次获取都会创建一个新的bean
         * @return
         */
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    

    配置类里注册该工厂bean

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

    测试方法:

            @Test
    	public void testFactoryBean() {
    		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig2.class);
    		//工厂bean获取的是调用getObject()方法创建的对象
    		Object bean1 = ac.getBean("colorFactoryBean");
    		Object bean2 = ac.getBean("colorFactoryBean");
    
    		System.out.println("bean的类型:"+bean1.getClass());
    		//单实例返回true  多实例返回false
    		System.out.println(bean1 == bean2);
    
    		//默认获取到的是工厂bean调用getObejct创建的对象
    		//要获取工厂bean本身,我们需要给id前面加一个&标识
    		Object bean3 = ac.getBean("&colorFactoryBean");
    		System.out.println("bean3的类型:"+bean3.getClass());
    
    	}
    

    运行结果: 单实例获取到的是相同的bean,加&之后获取到的bean为ColorFactoryBean

    ColorFactoryBean=========getObject=====
    bean的类型:class com.eric.bean.Color
    true
    bean3的类型:class com.eric.condition.ColorFactoryBean
    

    总结

    给容器中注册组件:

    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前面加一个&

    ok,组件注册完结,撒花。

    bk