前言
本文旨在為讀者解析Spring源碼中的關(guān)鍵類,以便讀者在深入閱讀源碼時,能夠了解關(guān)鍵類的作用和用途。在閱讀Spring源碼時,經(jīng)常會遇到一些不熟悉的概念,了解關(guān)鍵類的作用可以幫助讀者更好地理解這些概念。
BeanDefinition
BeanDefinition是Spring框架中的一個重要概念,它定義了一個Bean的基本屬性和行為,比如:
- BeanClassName,當(dāng)前的bean名字
- Scope,是否單例,具體枚舉:#SCOPE_SINGLETON、#SCOPE_PROTOTYPE
- LazyInit,是否懶加載,默認(rèn)不是
- DependsOn,是否依賴其他bean,如果依賴,則會先創(chuàng)建依賴bean
- InitMethodName,初始化方法名稱
- DestroyMethodName,銷毀類方法名稱
- ......還有更多,但是這幾個大體已經(jīng)差不多了
BeanDefinition的作用非常重要,它可以幫助Spring容器更好地管理Bean的生命周期和依賴關(guān)系。在Spring框架中,我們經(jīng)常會通過注解方式來定義Bean:
- < bean/>
- @Bean
- @Component(@Controller、@Service)
這些都是被稱為申明式定義Bean。就是使用Spring提供好的封裝。
除了注解方式,我們還可以通過編程方式來定義Bean,這時就需要直接使用BeanDefinition來創(chuàng)建BeanDefinition對象,并設(shè)置對應(yīng)的屬性,然后將其注冊到Spring容器中,比如
// 創(chuàng)建一個Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(UserService.class);
//當(dāng)然還可以設(shè)置其他上面我說的其他屬性:懶加載什么的
applicationContext.registerBeanDefinition("userService", beanDefinition);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
無論是通過注解方式還是編程方式來定義Bean,最終都是需要使用BeanDefinition來描述Bean的基本屬性和行為,然后將其放入Spring容器中進(jìn)行管理。
BeanDefinitionReader
BeanDefinitionReader是Spring框架中的一個重要組件,主要用于讀取和操作BeanDefinition對象。雖然我們在使用Spring框架時很少直接使用BeanDefinitionReader,但在Spring源碼中卻扮演著非常重要的角色,相當(dāng)于Spring源碼的基礎(chǔ)設(shè)施。
BeanDefinitionReader的核心方法包括以下幾個:
- BeanDefinitionRegistry,用來注冊bean定義,相當(dāng)于一個工廠
- BeanNameGenerator,用來生成bean名字的生成器
- loadBeanDefinitions,從資源中加載bean
XmlBeanDefinitionReader
XmlBeanDefinitionReader是BeanDefinitionReader的子類,可以用于從XML文件中讀取BeanDefinition并注冊到Spring容器中。使用XmlBeanDefinitionReader的步驟如下:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
//加載xml中配置的所有<bean>
int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
System.out.println(context.getBean("userService"))
AnnotatedBeanDefinitionReader
細(xì)心的朋友,應(yīng)該可以發(fā)現(xiàn)AnnotatedBeanDefinitionReader是一個單獨(dú)的類,不是BeanDefinitionReader的子類,但它的方法與BeanDefinitionReader基本相同,官方說是方便的適配器,用于編程注冊bean類,他可以解析@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description相關(guān)注解,具體操作如下:
// 創(chuàng)建一個Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
// beanDefinition.setBeanClass(UserService.class);
// applicationContext.registerBeanDefinition("userService", beanDefinition);
new AnnotatedBeanDefinitionReader(applicationContext).registerBean(UserService.class);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
同樣的,他也可以讓我們注冊的bean走完創(chuàng)建的整個生命周期過程。
ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner也是一個用于注冊BeanDefinition的工具類,與BeanDefinition接口沒有直接關(guān)系。ClassPathBeanDefinitionScanner可以掃描指定包路徑下帶有特定注解的類,并將其解析成BeanDefinition,注冊到Spring容器中。主要是他有個scan方法對我們定義的basepackage包路徑進(jìn)行解析掃描所有帶有@component、@ManagedBean(JSR-250標(biāo)準(zhǔn))、@Named(JSR-330標(biāo)準(zhǔn))
使用ClassPathBeanDefinitionScanner的步驟如下:
// 創(chuàng)建一個Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
new ClassPathBeanDefinitionScanner(applicationContext).scan("com.xiaoyu");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
BeanFactory
BeanFactory是Spring框架中的一個重要接口,他就是Spring用于管理Bean對象的創(chuàng)建和管理,看他的幾個主要方法就知道了:
- getBean,可以根據(jù)name、type等獲取bean對象
- containsBean,是否bean工廠中有某個對象
- isSingleton,判斷是否是單例
- isTypeMatch,判斷改name是否匹配類型
- getType,根據(jù)bean名字獲取類型
- getAliases。獲取別名數(shù)組
看著主要幾個接口實(shí)現(xiàn),基本都是圍繞bean所做的,然后根據(jù)接口再看他的實(shí)現(xiàn)類就方便許多了,
DefaultListableBeanFactory
如果看過源碼的朋友肯定對這個實(shí)現(xiàn)類不陌生,如果對這個實(shí)現(xiàn)類陌生的朋友,那請記住這個重要的實(shí)現(xiàn)類,它實(shí)現(xiàn)了很多接口、且繼承了多層父類,所以他的功能也是相當(dāng)之多。我們來看看他的主要方法:
- containsBeanDefinition,查看是否包含某個bean定義,因為該類維護(hù)了一個Map<String, BeanDefinition> beanDefinitionMap屬性。
- determineAutowireCandidate,決定注入哪個bean,@Primary-->優(yōu)先級最高--->name
- doResolveDependency,解析依賴,進(jìn)行注入
- registerBeanDefinition,注冊bean定義到beanDefinitionMap屬性
- preInstantiateSingletons,進(jìn)行創(chuàng)建bean實(shí)例
具體使用操作也是基本類似的
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(UserService.class);
defaultListableBeanFactory.registerBeanDefinition("userService",beanDefinition);
UserService userService1 = (UserService) defaultListableBeanFactory.getBean("userService");
userService1.test();
從他的結(jié)構(gòu)圖也能看出來:
AbstractBeanFactory
該類是抽象bean,介紹他主要目的就是getbean時,走的主要邏輯就是該類實(shí)現(xiàn)的dogetbean方法(請記住這個重要的方法),所以確實(shí)需要關(guān)注下,主要方法如下:
- doGetBean,獲取bean的主要邏輯,沒有則創(chuàng)建
- getMergedBeanDefinition,bean定義的合并邏輯,主要是將父類beanfactory中的屬性被子類覆蓋
AbstractAutowireCapableBeanFactory
繼承自剛才提到的AbstractBeanFactory,主要方法如下:
- autowireByName,按照name注入
- autowireByType,根據(jù)類型
- createBean,創(chuàng)建bean流程,實(shí)例化前可以使用BeanPostProcessors后置處理器
- createBeanInstance,正在創(chuàng)建bean,這邊使用到了之前入門講過的推斷構(gòu)造器實(shí)現(xiàn)實(shí)例化
- doCreateBean,創(chuàng)建bean,循環(huán)依賴、屬性填充、初始化
- initializeBean,初始化bean,包括初始化前、初始化、初始化后
- instantiateUsingFactoryMethod,利用factorymethod初始化bean
- invokeAwareMethods,初始化bean時的回調(diào)函數(shù)Aware接口
- populateBean,初始化之前,屬性賦值
可以從他的關(guān)鍵方法看出,主要作用就是初始化bean的全過程,也是很重要的類
HierarchicalBeanFactory
這里說下HierarchicalBeanFactory類,他只是一個接口類,但是如果想要使用beanfactory的層次結(jié)構(gòu),例如獲取父beanfactory,那就必須實(shí)現(xiàn)HierarchicalBeanFactory類,比如前面說的bean定義的合并邏輯,就需要獲取父beanfactory,從而實(shí)現(xiàn)父子bean定義的覆蓋合并
ApplicationContext
ApplicationContext是個接口,實(shí)際上也是一個BeanFactory,不過比BeanFactory
更加強(qiáng)大,它本身并沒有太多方法,但是它繼承了很多接口,因為接口之間是可以多繼承的。
關(guān)于他的父接口,這里不做多說明,詳情的話請看下子文章(后續(xù)更新)。
AnnotationConfigApplicationContext
一看這個類,大家都知道了,我們用的實(shí)例全是用這個類去啟動我們的spring的,我們看看他的主要方法:
- AnnotationConfigApplicationContext,構(gòu)造器,會初始化DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner;然后開始調(diào)用refresh()方法。
- register,會使用編程式定義將bean注入spring容器。就如我們的APPConfig
- scan,走ClassPathBeanDefinitionScanner的scan,掃描包路徑,將聲明式的bean注入進(jìn)spring容器
- setBeanNameGenerator,bean名稱生成器
ClassPathXmlApplicationContext
主要就是去解析xml配置的bean定義將其注入到spring容器中,功能其實(shí)跟AnnotationConfigApplicationContext類似,但是卻沒有AnnotationConfigApplicationContext強(qiáng)大,比如不能注冊BeanDefinition。
BeanPostProcessor
BeanPostProcess表示Bena的后置處理器,可以有多個BeanPostProcessor,我們自己也可以去定義一個BeanPostProcessor;
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if ("userService".equals(beanName)) {
System.out.println("userService");
return new User();
}
System.out.println("MyBeanPostProcessor.postProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("MyBeanPostProcessor.postProcessAfterInitialization");
return bean;
}
我們可以通過實(shí)現(xiàn)bean的后置處理器,來對某一個bean或者所有bean的進(jìn)行干預(yù),博主只是隨便寫了一個,沒有什么太大意義。
BeanFactoryPostProcessor
BeanFactoryPostProcessor表示Bean工廠的后置處理器,其實(shí)和BeanPostProcessor類似,BeanPostProcessor是干涉Bean的創(chuàng)建過程,BeanFactoryPostProcessor是干涉BeanFactory的創(chuàng)建過程,我們也可以自定義:
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("加工beanFactory");
}
}
FactoryBean
FactoryBean和BeanFactory不是一個東西,大家不要混淆兩個概念,BeanFactory是管理我們注入的bean等,而FactoryBean本身也會被Spring管理,一旦Spring知道我們的bean實(shí)現(xiàn)了FactoryBean,那么會自動調(diào)用getObject方法獲取我們自己創(chuàng)建的bean,這個bean完完全全交給我們自己創(chuàng)建了,我們可以這樣定義一個FactoryBean:
@Component
public class MyFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
UserService service = new UserService();
return service;
}
@Override
public Class<?> getObjectType() {
return UserService.class;
}
}
但是需要注意的是,這些注入UserService時,是不會有屬性依賴注入的,畢竟他沒有走bean的生命創(chuàng)建周期。細(xì)心的朋友會發(fā)現(xiàn),這根我在配置類中寫@bean形式的類有啥區(qū)別,現(xiàn)象來講,他倆都可以被創(chuàng)建出來,但是值得一提的是,F(xiàn)actoryBean創(chuàng)建出來的bean是沒走spring定義的bean生命周期的。
MetadataReader、ClassMetadata、AnnotationMetadata
Spring啟動時需要掃描指定包路徑下的所有類文件來獲取需要注入或管理的Bean信息。然而,并非所有類都是需要的,這時可以使用ASM技術(shù)來解析類文件的元數(shù)據(jù)信息,包括類上的注解信息和類的基本信息。ASM技術(shù)可以在運(yùn)行時動態(tài)生成和修改Java字節(jié)碼,從而高效地解析類文件的元數(shù)據(jù)信息,避免了大量的IO操作和類加載,提高了應(yīng)用的性能。以下是一個簡單的實(shí)例:文章來源:http://www.zghlxwxcb.cn/news/detail-419498.html
SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.xiaoyu.service.UserService");
System.out.println(metadataReader.getClassMetadata().getClassName());
metadataReader.getAnnotationMetadata().getAnnotationTypes().forEach(System.out::println);
結(jié)語
通過本文的解析,我們大致了解了Spring框架中的一些關(guān)鍵組件及其用途,這有助于我們在深入理解Spring源碼過程中建立起一個整體框架。Spring源碼量很大,要真正理解透徹還需要投入大量時間進(jìn)行細(xì)致學(xué)習(xí)和總結(jié)。但如果先對一些關(guān)鍵組件有一個大致的認(rèn)識,有助于我們進(jìn)行針對性學(xué)習(xí),避免迷失在繁雜的細(xì)節(jié)中。希望本文能夠?qū)ψx者有一定的幫助,更希望讀者在學(xué)習(xí)Spring源碼的過程中,不斷總結(jié)和提高,并在一定階段有所突破。祝讀者順利文章來源地址http://www.zghlxwxcb.cn/news/detail-419498.html
到了這里,關(guān)于Spring源碼系列:核心概念解析的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!