Spring組件註冊

Spring組件註冊

@Configuration

@Configuration註解告訴Spring這是一個配置類linux

@Bean

@Bean註解是給容器中註冊一個Bean,類型是返回值的類型,id默認是方法名做爲idspring

@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})windows

@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容器中加載的組件默認是單實例的。session

做用域範圍即value的可取值範圍ide

  • 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加上懶加載的註解以後容器啓動時不建立對象,第一次使用時纔會去建立對象並初始化。prototype

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

@Conditional

@Conditional按照必定的條件進行判斷,知足條件給容器中註冊beancode

標在方法上,表示這個方法知足必定條件纔會生效。component

標在類上,類中組件統一設置,表示知足當前條件,這個類中配置的全部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,組件註冊完結,撒花。

相關文章
相關標籤/搜索