- @Configuration
- @Bean
//@Bean//給容器注入一個bean,類型爲返回值的類型,id默認方法名就是id @Bean("person")//指定id爲person public Person person(){ return new Person("李四",12); }
<!-- 該註解對應的xml實現方式 --> <bean id="persion" class="indi.com.bean.Person"> <property name="name" value="張三"></property> <property name="age" value="18"></property> </bean>
- 默認是單例的
- 設置爲多實例:@Scope
- @Scope
//@Bean//給容器注入一個bean,類型爲返回值的類型,id默認方法名就是id @Scop("prototype") @Bean("person")//指定id爲person public Person person(){ return new Person("李四",12); }
<!-- 該註解對應的xml實現方式 --> <bean id="persion" class="indi.com.bean.Person" scope="prototype"> <property name="name" value="張三"></property> <property name="age" value="18"></property> </bean>
- singleton:單實例(默認):IOC容器啓動器會調用方法創建對象放到IOC容器中,以後每次使用時都直接從容器(map.get())中拿。
- prototype:多實例:IOC容器啓動器時並不會調用方法創建對象放到容器中,每次獲取時纔會調用方法創建對象,每次獲取都會調用方法創建對象。
- request:同一次請求創建一個實例
- session:同一個session創建一個實例
- @Lazy:針對單實例bean
- 單實例bean:默認容器加載時創建對象
- 使用@Lazy:容器加載時不創建對象,第一次使用(獲取)bean對象時創建對象並初始化
@Lazy @Bean("person")//指定id爲person public Person person(){ return new Person("李四",12); }
- @Conditional:
- 按照一定的條件判斷,滿足條件時給容器註冊bean
- 可以放在方法上,也可以放在類上(類中組件統一設置)
- 使用方法:
- 寫Condition的實現類
package indi.com.config; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; public class LinuxCondition implements Condition { /** * * @param conditionContext:判斷條件使用的上下文(環境) * @param annotatedTypeMetadata:註釋信息 * @return */ 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 person = registry.containsBeanDefinition("person"); //獲取系統信息 String property = environment.getProperty("os.name"); if(property.contains("linux")){ return true; } return false; } }
-
註解
package indi.com.config; import indi.com.bean.Person; import org.springframework.context.annotation.*; import org.springframework.stereotype.Controller; import org.springframework.stereotype.Service; @Configuration @ComponentScan(value="indi.com") public class BeanConfig { @Conditional({LinuxCondition.class}) @Bean("linux") public Person linux(){ return new Person("linux",55); } }
- 寫Condition的實現類
- @ComponentScan
- value:指定要掃描的包
@ComponentScan(value="indi.com")
<!-- 該註解對應的xml實現方式 --> <context:component-scan base-package="indi.com"></context:component-scan>
- excludeFilters = Filter[]:掃描時排除指定的組件
@ComponentScan(value="indi.com",excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})})
- includeFilters=Filter[]:掃描時只需要包含指定的組件
- 需要禁用默認的掃描規則:userDefaultFilters=false;
@ComponentScan(value="indi.com",includeFilters = {@ComponentScan.Filter(type=FilterType.ANNOTATION,classes ={Controller.class})},useDefaultFilters = false)})
<!-- 該註解對應的xml實現方式 --> <context:component-scan base-package="indi.com" use-default-filters="false"></context:component-scan>
- 需要禁用默認的掃描規則:userDefaultFilters=false;
- @Filter
- type
- FilterType.ANNOTATION:按照註解
type=FilterType.ANNOTATION
- FilterType.ASSIGNABLE_TYPE:按照給定的類型
type=FilterType.ASSIGNABLE_TYPE
- FilterType.ASPECTJ:按照ASPECTJ表達式
- FilterType.REGEX:按照正則
- FilterType.CUSTOM:自定義規則
- 寫一個TypeFilter的實現類:MyTypeFilter
package indi.com.config; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; import java.io.IOException; public class MyTypeFilter implements TypeFilter { /** * * @param metadataReader:讀取當前正在掃描的類的信息 * @param metadataReaderFactory:可以獲取其他任何類的信息 * @return * @throws IOException */ 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; } }
- 配置
@ComponentScan(value="indi.com",@Filter(type=FilterType.CUSTOM,class={MyTypeFilter}))
- 注意:根據MyTypeFilter的規則可知,在indi.com包下,所有類名中包含"er"的類(無論該類上是否有註解)都能掃描到
- 寫一個TypeFilter的實現類:MyTypeFilter
- FilterType.ANNOTATION:按照註解
- type
- value:指定要掃描的包
- @ComponentScans
- @Import
- 方式一:
//id默認是組件的全類名 @Import(類名.class)或者@Import({類名1.class,類名2.class})
- 方式二:
- 寫一個類實現ImportSelector
package indi.com.config; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; //自定義邏輯返回需要導入的組件 public class MyImportSelector implements ImportSelector { /** * * @param annotationMetadata:當前標註@Import註解的類的所有註解信息 * @return:導入到容器中的組件全類名 */ public String[] selectImports(AnnotationMetadata annotationMetadata) { //return new String[0];//默認 return new String[]{類1的全路徑,類2的全路徑}; } }
- 配置
//id默認是組件的全類名 @Import(類名.class)或者@Import({類名1.class,類名2.class,MyImportSelector.class})
- 寫一個類實現ImportSelector
- 方式三:
- 寫一個類實現ImportBeanDefinitionRegistrar
package indi.com.config; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * * @param annotationMetadata:當前類的註解信息 * @param beanDefinitionRegistry:beanDefinition註冊類 * 將所有需要添加到容器中的bean, * 通過beanDefinitionRegistry.registerBeanDefinition手工註冊進來 */ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { boolean test = beanDefinitionRegistry.containsBeanDefinition("類的全路徑"); if(test){ RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(類.class); beanDefinitionRegistry.registerBeanDefinition("test",rootBeanDefinition); } } }
- 配置
//id默認是組件的全類名 @Import(類名.class)或者@Import({類名1.class,類名2.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
- 寫一個類實現ImportBeanDefinitionRegistrar
- 方式一:
- FactoryBean(工廠Bean)
- 創建Spring定義的FactoryBean,實現FactoryBean
- 將創建的FactoryBean加入容器中
- 注意:工廠Bean獲取的是調用getObject創建的對象
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(); Object bean = applicationContext.getBean("工具bean的註冊ID");
- 獲取工廠Bean本身:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(); Object bean = applicationContext.getBean("&工具bean的註冊ID");
- 注意:工廠Bean獲取的是調用getObject創建的對象
總結:給容器中註冊組件
- 包掃描+組件標註註解(@Controller、@Service、@Repository、@Component)
- @Bean:導入第三方包裏面的組件
- @Import:快速給容器中導入一個組件
- @Import(類名.class):容器中自動導入這個組件,id默認爲全類名
- ImportSelector:返回需要導入的組件的全類名數組
- ImportBeanDefinitionRegistrar:手動註冊bean到容器中
- 使用Spring提供的FactoryBean
- 默認獲取的是工廠bean調用的getObject創建的對象
- 要獲取工廠bean本身,需要給id前面加一個&