整理一下之前Spring的學習筆記,大致有一下幾種Spring注入到容器中的方法:
1)、配置在xml的方式。
2)、開啟包掃描@ComponentScan使用@Component,@Service,@Controller,@Repository(其實后三個都繼承@Component)注冊組件到spring容器里面
3)、使用@Bean注入
4)、使用@Import快速導入組件
@Configuration
? 聲明為配置類,與bean.xml一致
XML方式注入
Sping最開始的用法,先定義好xml文件,使用ClassPathXmlApplicationContext()加載指定xml文件就創建好容器了,當Bean過多的時候,使用xml配置就顯得比較繁瑣,所以在現在的大環境下,這種注入方法已經過時了,就簡單的提一下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user" class="com.test.SpringCoreTest.test00.bean.User"><property name="name" value="Tom"></property><property name="age" value="12"></property></bean></beans>
@ComponentScan
需和@Configuration注解一起使用,與xml當中的<context:component-scan base-package="" />一致,表示掃描指定包下的類將帶有@Component注解的類全部掃描到容器當中
有幾個常用的參數需了解一下:
basePackages: 掃描指定包下的類并且注入到spring容器里面
useDefaultFilters:是否使用默認過濾器,和excludeFilters、includeFilters配置一起使用
includeFilters:包含過濾器為過濾的內容,當useDefaultFilters為false的時候才生效
excludeFilters:去除指定過濾器過濾的內容,當useDefaultFilters為true的時候才能生效
過濾器為@ComponentScan的內部注解類@Filter:
? ? ? classes:指定類,與type搭配使用
?? ? ? ?type:過濾器的類型org.springframework.context.annotation.FilterType.class枚舉類中(共有五種,僅記錄三種經常使用的類型)
? ? ? ? ? ?? ANNOTATION:指定過濾哪些注解,例如@Controller
? ? ? ? ? ?? ASSIGNABLE_TYPE:指定過濾哪些類
? ? ? ? ? ?? CUSTOM:自定義過濾器,可繼承TypeFilter接口,實現match方法
示例:
public class SpringTest01Filter implements TypeFilter {/*** @param metadataReader 讀取當前掃描類的信息* @param metadataReaderFactory 可以獲取其他任何類的信息*/public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)throws IOException {//獲取當前注解信息ClassMetadata classMetadata = metadataReader.getClassMetadata();//獲取當前掃描類的信息String className = classMetadata.getClassName();System.out.println("====>>>>"+className);if(className.contains("er"))//如果當前掃描類信息包含er的時候,注入到Spring容器return true;elsereturn false;}}//配置類
@ComponentScan(basePackages="com.test.SpringCoreTest.test01.config",includeFilters= {@Filter(type = FilterType.CUSTOM,classes= {SpringTest01Filter.class})
},useDefaultFilters=true)
@Configuration
這里會有個問題,為什么在使用過濾器的時候對useDefaultFilters有要求?源碼中解析:
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
//該段代碼中獲取了useDefaultFilters的值
//進入該類中
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,Environment environment, @Nullable ResourceLoader resourceLoader) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");this.registry = registry;if (useDefaultFilters) {registerDefaultFilters();//useDefaultFilters為true時,該方法開啟了注冊默認過濾器的方法}setEnvironment(environment);setResourceLoader(resourceLoader);}//進入到registerDefaultFilters方法里面
protected void registerDefaultFilters() {//執行了當前方法重置了includeFilters包含的過濾器,導致帶有Component注解的類都會加載到容器里面,所以在useDefaultFilters為true的情況下includeFilters失效的原因在此this.includeFilters.add(new AnnotationTypeFilter(Component.class));ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();try {this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.}try {this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-330 API not available - simply skip.}}
@Bean
需和@Configuration一起使用,容器中的key為方法名,bean為返回的對象,默認為單例。示例:
@Configuration
public class SpringConfig01 {@Beanpublic User user() {return new User();}//....
}
以下三個注解可以和@Bean一起使用:
@Scope
? 指定容器組件類型
? prototype:多例模式,當容器創建時,并不會創建對象,而是在調用時創建一個新的對象
? singleton:單例模式,容器創建時,對象也會創建
? request:主要是針對web應用,每提交一次請求,都回去創建一個對象
? session:針對web應用,創建一個session創建一個對象
@Lazy
? 懶加載只有當前組件第一次被調用的時候才會去創建對象,針對單例模式
@Conditional
? 可指定在某些條件下,才能將當前組件注入到容器,
? 參數為繼承org.springframework.context.annotation.Condition.class的實現類
/*** @param context 可以使用ApplicationContext(上下文)* @param metadata 可以獲取到注解信息*/public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {//獲取到BeanFactoryConfigurableListableBeanFactory beanFactory = context.getBeanFactory();//可獲取環境參數,如jvm環境,spring環境等等Environment environment = context.getEnvironment();String osName = environment.getProperty("os.name");if(osName.contains("Windows"))//如果當前環境為window,則創建當前組件并加載到容器中return true;return false;}
@Import
??快速導入組件,共三種形式,這個算是一個比較主要的注入方式吧,在Spring中,需要做一些擴展的時候都會需要用到這個,比如:mybatis-spring融合,開啟AOP功能等使用的就是這里的第三種方式
1)、@Import(value = { Dog.class,Cat.class })//快速導入到容器中,以類的全路徑作為bean的ID
2)、@Import(value = { SpringTest03ImportSelector.class })//實現ImportSelector接口
public class SpringTest03ImportSelector implements ImportSelector {public String[] selectImports(AnnotationMetadata importingClassMetadata) {//返回為類的全類名return new String [] {};//注意一下,這邊必須返回一個空的數組,不然啟動報錯空指針異常}}//在源碼org.springframework.context.annotation.ConfigurationClassParser.class類中
private Collection<SourceClass> asSourceClasses(String... classNames) throws IOException {List<SourceClass> annotatedClasses = new ArrayList<>(classNames.length);//這里的classNames為之前ImportSelector返回的數組,為null的話即報錯for (String className : classNames) {annotatedClasses.add(asSourceClass(className));}return annotatedClasses;}
3)、@Import(value = { SpringTest03ImportBeanDefinitionRegistrar.class })//實現ImportBeanDefinitionRegistrar接口,所有的bean注冊都會使用到該接口進行注冊
/*** @param importingClassMetadata 當前類的注解信息 * @param registry BeanDefinition的注冊類* 可做條件修改*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {boolean b1 = registry.containsBeanDefinition("user");if(b1) {registry.registerBeanDefinition("pig", new RootBeanDefinition(Pig.class));}
?
?