AnnotationConfigApplicationContext 源碼分析(一):新建對象
本文是作者的個人學(xué)習(xí)筆記,僅做參考,Spring代碼版本5.2.2
AnnotationConfigApplicationContext 作為繼承GenericApplicationContext的子類,歸屬于Spring容器。同時該類實現(xiàn)了AnnotationConfigRegistry注解,在GenericApplicationContext的基礎(chǔ)上為容器添加了一下兩個功能:
對攜帶spring注解的類的注冊。
掃描某個包下攜帶spring注解的類。
一、AnnotationConfigApplicationContext的基本使用
public class DemoApplication {
public static void main(String[] args) {
//1.新建AnnotationConfigApplicationContext對象
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//2.注冊配置類
applicationContext.register(MyConfiguration.class);
//3.啟動容器
applicationContext.refresh();
//4.停止容器
applicationContext.stop();
//5.重啟容器
applicationContext.start();
//6.關(guān)閉容器
applicationContext.close();
}
}
在AnnotationConfigApplicationContext最基礎(chǔ)的使用中,我們啟動一個容器需要三個步驟,對應(yīng)上面的代碼
- 新建AnnotationConfigApplicationContext對象
- 注冊配置類
- 啟動容器
剩下的三個步驟一般不會使用,有時間也將會閱讀做分析
- 停止容器
- 重啟容器
- 關(guān)閉容器
二、新建AnnotationConfigApplicationContext對象
/**
*
**/
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
* 創(chuàng)建一個新的AnnotationConfigApplicationContext,它需要通過{@link#register}調(diào)用填充,
* 然后手動{@linkplain#刷新}。
*
* 這里初始化了
*/
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
// Spring的掃描機(jī)制
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
// 內(nèi)置一個DefaultListableBeanFactory對象
super(beanFactory);
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
}
由上面我們可以看到新建一個AnnotationConfigApplicationContext對象的時候,將實例化兩個類,同時選擇性的內(nèi)置一個DefaultListableBeanFactory對象,以下將做具體的解析
1、 DefaultListableBeanFactory
這個類同GenericApplicationContext一樣,都實現(xiàn)了BeanFactory接口,作為容器使用,但是兩者沒有繼承關(guān)系。
GenericApplicationContext一般作為資源管理器使用,內(nèi)部對于bean的管理往往是通過內(nèi)置一個DefaultListableBeanFactory對象作為Bean管理器。
2、AnnotatedBeanDefinitionReader
/**
* Convenient adapter for programmatic registration of bean classes.
* <p>This is an alternative to {@link ClassPathBeanDefinitionScanner}, applying
* the same resolution of annotations but for explicitly registered classes only.
* 便于bean類的編程注冊的適配器。
* <p>這是{@link ClassPathBeanDefinitionScanner}的另一種選擇,它應(yīng)用相同的注釋解析,但僅適用于顯式注冊的類。
*/
public class AnnotatedBeanDefinitionReader {}
AnnotatedBeanDefinitionReader作為一個工具類,用于更方便的注冊bean,接下來我們看一下這個類的構(gòu)造函數(shù)
public class AnnotatedBeanDefinitionReader {
private final BeanDefinitionRegistry registry;
private ConditionEvaluator conditionEvaluator;
/**
* Create a new {@code AnnotatedBeanDefinitionReader} for the given registry,
* using the given {@link Environment}.
* @param registry the {@code BeanFactory} to load bean definitions into,
* in the form of a {@code BeanDefinitionRegistry}
* @param environment the {@code Environment} to use when evaluating bean definition
* profiles.
*
* 使用給定的{@link Environment},為給定的注冊表創(chuàng)建一個新的{@code AnnotatedBeanDefinitionReader}。
* @param registry 以{@code BeanDefinitionRegistry}的形式將bean定義加載到{@code BeanFactory}
* @param environment 在計算bean定義概要文件時要使用的{@code Environment}。
* @since 3.1
*/
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
}
由上面代碼可以看到,AnnotatedBeanDefinitionReader實例化需要的兩個參數(shù):
- BeanDefinitionRegistry:bean定義的注冊器,由GenericApplicationContext實現(xiàn),AnnotationConfigApplicationContext繼承。
- Environment:環(huán)境變量,這里先不討論,后面補(bǔ)充
AnnotatedBeanDefinitionReader實例化的邏輯:
- 持有一個BeanDefinitionRegistry/bean定義的注冊器
- 通過registry,environment參數(shù)創(chuàng)建一個ConditionEvaluator對象,ConditionEvaluator對象的作用是用于解析注解@Conditional,這里先不做過多關(guān)注
- 通過工具類AnnotationConfigUtils,注冊AnnotationConfigProcessors
接下來我們一次看一下ConditionEvaluator對象的創(chuàng)建和解析AnnotationConfigProcessors的注冊
ConditionEvaluator對象的創(chuàng)建
/**
* Internal class used to evaluate {@link Conditional} annotations.
* 用于計算{@link Conditional}批注的內(nèi)部類。
*
*/
class ConditionEvaluator {
private final ConditionContextImpl context;
/**
* Create a new {@link ConditionEvaluator} instance.
* 用于計算{@link Conditional}批注的內(nèi)部類。
*/
public ConditionEvaluator(@Nullable BeanDefinitionRegistry registry,
@Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
this.context = new ConditionContextImpl(registry, environment, resourceLoader);
}
}
注冊AnnotationConfigProcessors
public abstract class AnnotationConfigUtils {
/**
* Register all relevant annotation post processors in the given registry.
* @param registry the registry to operate on
* @param source the configuration source element (already extracted)
* that this registration was triggered from. May be {@code null}.
* @return a Set of BeanDefinitionHolders, containing all bean definitions
* that have actually been registered by this call
*
* 注冊在給定的注冊表中所有相關(guān)的批注后置處理器。
* @param source 觸發(fā)此注冊的配置源元素(已提取)??赡苁莧@code null}。
* @return 一組BeanDefinitionHolders,包含此調(diào)用實際注冊的所有bean定義
*/
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
//步驟一
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
//步驟二
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
。。。
return beanDefs;
}
}
上面代碼將分成幾部分步驟:
- 獲取DefaultListableBeanFactory對象,
- 需要注意的是,;
- 如果beanFactory(DefaultListableBeanFactory不為空),將為該對象設(shè)置兩個對象,這里不做討論:
- AnnotationAwareOrderComparator
- ContextAnnotationAutowireCandidateResolver
- 為當(dāng)前容器registry注冊多個BeanFactory后置處理器
- 注冊的過程
- 利用后置處理器類對象和source對象(配置)生成一個BeanDefinition(Bean定義)對象;
- 用指定的bean名稱和BeanDefinition對象,一起注冊到registry中,并返回一個BeanDefinitionHolder對象(該對象持有BeanDefinition對象,bean的名稱,bean的別名列表)
- 將BeanDefinitionHolder添加到指定列表中,作為最后的結(jié)果返回,這里并無利用到結(jié)果。
- BeanFactory后置處理器將干預(yù)Spring在注冊,掃描,解析,生成BeanDefinition等的整個過程,后面將會具體解析。
- Spring支持用戶注冊自定義的BeanFactory后置處理器,同時,Spring在不同的容器中也注冊實現(xiàn)不同功能的后置處理器,以下是在當(dāng)前方法中注冊的跟注解相關(guān)的后置處理器的簡單介紹,在后面調(diào)用中將做具體解析
- CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME:
- 作用:內(nèi)部托管配置注釋處理器。
- 對應(yīng)的類:ConfigurationClassPostProcessor.class
- AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME
- 作用:內(nèi)部管理的自動注入注解處理器
- 對應(yīng)的類:AutowiredAnnotationBeanPostProcessor.class
- COMMON_ANNOTATION_PROCESSOR_BEAN_NAME
- 作用:內(nèi)部管理的JSR-250注釋處理器
- 對應(yīng)的類:CommonAnnotationBeanPostProcessor.class
- PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME
- 作用:內(nèi)部管理的JPA注釋處理器(不一定注入)。
- 對應(yīng)的類:PersistenceAnnotationBeanPostProcessor.class
- EVENT_LISTENER_PROCESSOR_BEAN_NAME
- 作用:內(nèi)部管理的@EventListener注釋處理器
- 對應(yīng)的類:EventListenerMethodProcessor.class
- EVENT_LISTENER_FACTORY_BEAN_NAME
- 作用:內(nèi)部管理的EventListenerFactory。
- 對應(yīng)的類:DefaultEventListenerFactory.class
- CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME:
- 注冊的過程
3、ClassPathBeanDefinitionScanner
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
/**
* Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and
* using the given {@link Environment} when evaluating bean definition profile metadata.
* @param registry the {@code BeanFactory} to load bean definitions into, in the form
* of a {@code BeanDefinitionRegistry}
* @param useDefaultFilters whether to include the default filters for the
* {@link org.springframework.stereotype.Component @Component},
* {@link org.springframework.stereotype.Repository @Repository},
* {@link org.springframework.stereotype.Service @Service}, and
* {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
* @param environment the Spring {@link Environment} to use when evaluating bean
* definition profile metadata
* @param resourceLoader the {@link ResourceLoader} to use
*
* 為給定的bean工廠創(chuàng)建一個新的{@code ClassPathBeanDefinitionScanner},
* 并在計算bean定義概要文件元數(shù)據(jù)時使用給定的{@link Environment}。
* @param registry 以{@code BeanDefinitionRegistry}的形式將bean定義加載到{@code BeanFactory}
* @param useDefaultFilters 是否包含
* {@link org.springframework.stereotype.Component@Component}、
* {@link org.springframework.stereotype.Repository@Repository}、
* {@link org.springframework.stereotype.Service@Service}和
* {@link org.springframework.stereotype.Controller@Controller}構(gòu)造型批注的默認(rèn)篩選器
* @param environment 在計算bean定義概要文件元數(shù)據(jù)時使用的Spring{@link Environment}
* @param resourceLoader 要使用的{@link ResourceLoader}
*
* @since 4.3.6
*/
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
//關(guān)鍵代碼,Spring 內(nèi)部默認(rèn)為true
//使用默認(rèn)的Filters
if (useDefaultFilters) {
registerDefaultFilters();
}
setEnvironment(environment);
setResourceLoader(resourceLoader);
}
}
ClassPathBeanDefinitionScanner故名思義,是專門用于掃描類并將符合條件的類注冊為BeanDefinition的工具對象。
ClassPathBeanDefinitionScanner構(gòu)造函數(shù)的三個參數(shù):
- registry(BeanDefinitionRegistry):
- useDefaultFilters(boolean):用于判斷是否使用默認(rèn)的注解過濾器(AnnotationTypeFilter)
- 注解過濾器/AnnotationTypeFilter:用于處理特定注解,有黑名單和白名單,先執(zhí)行黑名單
- 黑名單/excludeFilters:標(biāo)記該注解的類將不會被解析成Bean,即使在白名單中存在
- 白名單/includeFilters:標(biāo)記該注解的類將會被解析成Bean
- 注解過濾器/AnnotationTypeFilter:用于處理特定注解,有黑名單和白名單,先執(zhí)行黑名單
- environment(Environment):
- resourceLoader(ResourceLoader):資源加載器,這里先不做描述
- 這里資源加載器指的是AnnotationConfigApplicationContext對象
- 繼承實現(xiàn)鏈為
- AnnotationConfigApplicationContext—>
- DefaultResourceLoader—>
- GenericApplicationContext—>
- AbstractApplicationContext—>
- DefaultResourceLoader—>
- ResourceLoader
構(gòu)造函數(shù)初始化的過程:
1. 持有一個BeanDefinitionRegistry/bean對象(定義的注冊器)
2. 判斷是否使用默認(rèn)的注解過濾器AnnotationTypeFilter.class,默認(rèn)為是,如果是將注冊以下注解
1. 白名單:@Component,@ManagedBean,@Named
2. 黑名單:無
3. 持有Environment對象
4. 通過resourceLoader對象生成對應(yīng)的對象被ClassPathBeanDefinitionScanner持有,暫時不解析以下類
1. resourcePatternResolver(ResourcePatternResolver):新建PathMatchingResourcePatternResolver對象
2. metadataReaderFactory(MetadataReaderFactory):新建CachingMetadataReaderFactory對象
3. componentsIndex(CandidateComponentsIndex):利用resourceLoader的類加載器新建CandidateComponentsIndex對象
總結(jié)
在實例化AnnotationConfigApplicationContext對象的時候,做了三件事情:
- 新建一個AnnotatedBeanDefinitionReader對象用于注冊一個類到容器中,而一般我們注冊的類通常是配置類;
- 同時注冊幾個BeanFactory后置處理器到容器中;
- 新建一個ClassPathBeanDefinitionScanner對象用于掃描和注冊類中。