javascript
Spring5源码 - Spring IOC 注解复习
文章目錄
- Pre
- xml配置文件
- JavaConfig
- @CompentScan
- 在配置類上寫@CompentScan注解來進行包掃描
- excludeFilters
- includeFilters
- @ComponentScan.Filter type的類型
- 使用自定義過濾器CUSTOM
- @Scope
- @Lazy
- @Conditional 條件判斷
Pre
為了更好地學習源碼,我們有必要對基礎知識進行一次簡單的復習,只有在知道如何使用的基礎上,再去閱讀源碼才能明白spring這些源碼是對哪些功能的支持。
這里簡單的梳理一下
xml配置文件
【配置文件 】
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="artisan" class="com.artisan.base.Artisan"/> </beans>【讀取Bean】
ClassPathXmlApplicationContext cx = new ClassPathXmlApplicationContext("classpath:spring.xml"); System.out.println(cx.getBean("artisan").getClass().getSimpleName());}【輸出】
JavaConfig
【POJO】
public class Bean1 { }【配置文件 】
@Configuration public class MainConfig {@Beanpublic Bean1 bean1(){return new Bean1();} }【讀取Bean— 傳入配置類】
public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig.class);System.out.println(ac.getBean("bean1"));}@Bean的形式, bean的默認名稱是方法名,若@Bean(value=“bean的名稱”) ,那么bean的名稱是指定的名稱。
【測試結果】
@CompentScan
在配置類上寫@CompentScan注解來進行包掃描
【配置類】
package com.artisan.base.componentscan.config;import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;@Configuration @ComponentScan("com.artisan.base.componentscan") public class CSMainConfig {}【c - s -d 】
package com.artisan.base.componentscan.controller;import org.springframework.stereotype.Controller;@Controller public class ArtisanInfoController { } package com.artisan.base.componentscan.service;import org.springframework.stereotype.Service;@Service public class ArtisanService { } package com.artisan.base.componentscan.dao;import org.springframework.stereotype.Repository;@Repository public class ArtisanDao { }【測試類】
package com.artisan.base.componentscan;import com.artisan.base.componentscan.config.CSMainConfig; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class CMTest {public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(CSMainConfig.class);// 輸出 單例池中的單例bean的名字for (String beanDefinitionName : ac.getBeanDefinitionNames()) {System.out.println("bdName:" + beanDefinitionName);}} }【輸出】
excludeFilters
【配置類】
import com.artisan.base.componentscan.service.ArtisanService; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.stereotype.Controller;@Configuration @ComponentScan(basePackages = {"com.artisan.base.componentscan"},excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {ArtisanService.class}) }) public class CSMainConfig {}重點配置
@ComponentScan(basePackages = {"com.artisan.base.componentscan"},excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {ArtisanService.class}) })excludeFilters(排除@Controller注解的,和ArtisanService的)
【測試結果】
includeFilters
@Configuration @ComponentScan(basePackages = {"com.artisan.base.componentscan"},includeFilters ={@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class})},useDefaultFilters = false)、 public class CSMainConfig {}若使用包含的用法, 需要把useDefaultFilters屬性設置為false(true表示掃描全部的)
【測試結果】
@ComponentScan.Filter type的類型
看下源碼
public enum FilterType {/*** Filter candidates marked with a given annotation.* @see org.springframework.core.type.filter.AnnotationTypeFilter*/ANNOTATION,/*** Filter candidates assignable to a given type.* @see org.springframework.core.type.filter.AssignableTypeFilter*/ASSIGNABLE_TYPE,/*** Filter candidates matching a given AspectJ type pattern expression.* @see org.springframework.core.type.filter.AspectJTypeFilter*/ASPECTJ,/*** Filter candidates matching a given regex pattern.* @see org.springframework.core.type.filter.RegexPatternTypeFilter*/REGEX,/** Filter candidates using a given custom* {@link org.springframework.core.type.filter.TypeFilter} implementation.*/CUSTOM}- ANNOTATION 注解形式 舉個例子比如 @Compent @Controller @Service @Repository .......
- ASSIGNABLE_TYPE 指定類型的 FilterType.ASSIGNABLE_TYPE 舉個例子
- ASPECTJ 類型的 FilterType.ASPECTJ 不常用
- REGEX 正則表達式的 FilterType.REGEX 不常用
- CUSTOM 自定義類型
使用自定義過濾器CUSTOM
package com.artisan.base.componentscan.customFilterType;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 ArtisanFilterType implements TypeFilter {@Overridezpublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {//獲取當前類的注解源信息AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();//獲取當前類的class的源信息ClassMetadata classMetadata = metadataReader.getClassMetadata();//獲取當前類的資源信息Resource resource = metadataReader.getResource();System.out.println("類的路徑:"+classMetadata.getClassName());// 排除包含Artisan的Beanif(classMetadata.getClassName().contains("Artisan")) {return true;}return false;} }【配置類】
@Configuration @ComponentScan(basePackages = {"com.artisan.base.componentscan"},excludeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, value = {ArtisanFilterType.class})}) public class CSMainConfig {}【測試結果】
@Scope
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-scopes
public class Bean2 {public Bean2() {System.out.println("Bean2 Created");} } public class Bean3 {public Bean3() {System.out.println("Bean3 Created");} }
【config】
package com.artisan.base.scope;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope;@Configuration public class Config {@Bean()public Bean2 bean2(){return new Bean2();}@Bean()@Scope(value = "prototype")public Bean3 bean3(){return new Bean3();}}【測試bean的加載】
package com.artisan.base.scope;import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class TestScope {public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);System.out.println("========================");// 每次調用都會實例化一個新的Bean3+System.out.println(ac.getBean("bean3"));System.out.println(ac.getBean("bean3"));} }【輸出】
【結論】
-
在不指定@Scope的情況下,所有的bean都是單實例的bean,而且是餓漢加載 即 容器啟動實例就創建好了
-
指定@Scope為 prototype 表示為原型bean,而且還是懶漢模式加載 , 即IOC容器啟動的時候,并不會創建對象,而是 在第一次使用的時候才會創建 ,并且每次調用,都會實例化一個新的對象
@Lazy
Bean的懶加載@Lazy 主要針對單實例的bean 容器啟動的時候,不創建對象,在第一次使用的時候才會創建該對象 ,后續調用不會新建對象,而是從單例池中獲取緩存的bean。
繼續使用上面的例子 ,給Bean2 加上Lazy注解
@Bean()@Lazypublic Bean2 bean2(){return new Bean2();}【測試】
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class TestScope {public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);System.out.println(ac.getBean("bean2"));System.out.println(ac.getBean("bean2"));} }【結果】
@Conditional 條件判斷
需求: 只有容器中有bean5 才裝載bean6
value 是一個class數組, 需要實現Condition 接口 , 那我們也弄個唄
【自定義Condition 】
package com.artisan.base.condition;import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata;public class ArtisanCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {//判斷容器中是否有Bean5 ,有的話 返回trueif(context.getBeanFactory().containsBean("bean5")) {return true;}return false;} }【config 】
package com.artisan.base.condition;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration;@Configuration public class CDConfig {@Beanpublic Bean5 bean5(){return new Bean5();}// Conditional的條件返回true,才裝載Bean6@Bean@Conditional(value = ArtisanCondition.class)public Bean6 bean6(){return new Bean6();}}【beans】
public class Bean5 {public Bean5() {System.out.println("Bean5 Created");} } public class Bean6 {public Bean6() {System.out.println("Bean6 Created");} }【正常情況】
package com.artisan.base.condition;import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class CDTest {public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(CDConfig.class);for (String beanDefinitionName : ac.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}} }我們看到了 CDConfig中 bean5 上標注了@Bean
現在我們把Bean5的@Bean去掉
總結
以上是生活随笔為你收集整理的Spring5源码 - Spring IOC 注解复习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: APM - 零侵入监控JDBC服务
- 下一篇: Spring5 - 向IOC容器中添加组