Spring組件註冊
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
總結
給容器中註冊組件:
- 包掃描+組件標註註解(@Controller/@Service/@Repository/@Component)
- @Bean 導入的第三方包裡面的組件
- @Import 快速給容器中導入一個組件
- @Import(要導入到容器中的組件):容器中就會自動註冊這個組件,id默認是全類名
- @ImportSelector 返回需要導入的組件的全類名數組
- @ImportBeanDefinitionRegistrar 手動註冊bean到容器中
- 使用Spring提供的FactoryBean(工廠Bean)
- 默認獲取到的是工廠bean調用getObject方法創建的對象
- 要獲取工廠Bean本身,我們需要給id前面加一個&
ok,組件註冊完結,撒花。
