本文旨在為讀者解析Spring原始碼中的關鍵類,以便讀者在深入閱讀原始碼時,能夠了解關鍵類的作用和用途。在閱讀Spring原始碼時,經常會遇到一些不熟悉的概念,瞭解關鍵類的作用可以幫助讀者更好地理解這些概念。
BeanDefinition是Spring框架中的一個重要概念,它定義了一個Bean的基本屬性和行為,比如:
BeanDefinition的作用非常重要,它可以幫助Spring容器更好地管理Bean的生命週期和依賴關係。在Spring框架中,我們經常會通過註解方式來定義Bean:
這些都是被稱為申明式定義Bean。就是使用Spring提供好的封裝。
除了註解方式,我們還可以通過程式設計方式來定義Bean,這時就需要直接使用BeanDefinition來建立BeanDefinition物件,並設定對應的屬性,然後將其註冊到Spring容器中,比如
// 建立一個Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(UserService.class);
//當然還可以設定其他上面我說的其他屬性:懶載入什麼的
applicationContext.registerBeanDefinition("userService", beanDefinition);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
無論是通過註解方式還是程式設計方式來定義Bean,最終都是需要使用BeanDefinition來描述Bean的基本屬性和行為,然後將其放入Spring容器中進行管理。
BeanDefinitionReader是Spring框架中的一個重要元件,主要用於讀取和操作BeanDefinition物件。雖然我們在使用Spring框架時很少直接使用BeanDefinitionReader,但在Spring原始碼中卻扮演著非常重要的角色,相當於Spring原始碼的基礎設施。
BeanDefinitionReader的核心方法包括以下幾個:
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是一個單獨的類,不是BeanDefinitionReader的子類,但它的方法與BeanDefinitionReader基本相同,官方說是方便的介面卡,用於程式設計註冊bean類,他可以解析@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description相關注解,具體操作如下:
// 建立一個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走完建立的整個生命週期過程。
ClassPathBeanDefinitionScanner也是一個用於註冊BeanDefinition的工具類,與BeanDefinition介面沒有直接關係。ClassPathBeanDefinitionScanner可以掃描指定包路徑下帶有特定註解的類,並將其解析成BeanDefinition,註冊到Spring容器中。主要是他有個scan方法對我們定義的basepackage包路徑進行解析掃描所有帶有@component、@ManagedBean(JSR-250標準)、@Named(JSR-330標準)
使用ClassPathBeanDefinitionScanner的步驟如下:
// 建立一個Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
new ClassPathBeanDefinitionScanner(applicationContext).scan("com.xiaoyu");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
BeanFactory是Spring框架中的一個重要介面,他就是Spring用於管理Bean物件的建立和管理,看他的幾個主要方法就知道了:
如果看過原始碼的朋友肯定對這個實現類不陌生,如果對這個實現類陌生的朋友,那請記住這個重要的實現類,它實現了很多介面、且繼承了多層父類別,所以他的功能也是相當之多。我們來看看他的主要方法:
具體使用操作也是基本類似的
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(UserService.class);
defaultListableBeanFactory.registerBeanDefinition("userService",beanDefinition);
UserService userService1 = (UserService) defaultListableBeanFactory.getBean("userService");
userService1.test();
從他的結構圖也能看出來:
該類是抽象bean,介紹他主要目的就是getbean時,走的主要邏輯就是該類實現的dogetbean方法(請記住這個重要的方法),所以確實需要關注下,主要方法如下:
繼承自剛才提到的AbstractBeanFactory,主要方法如下:
可以從他的關鍵方法看出,主要作用就是初始化bean的全過程,也是很重要的類
這裡說下HierarchicalBeanFactory類,他只是一個介面類,但是如果想要使用beanfactory的層次結構,例如獲取父beanfactory,那就必須實現HierarchicalBeanFactory類,比如前面說的bean定義的合併邏輯,就需要獲取父beanfactory,從而實現父子bean定義的覆蓋合併
ApplicationContext是個介面,實際上也是一個BeanFactory,不過比BeanFactory
更加強大,它本身並沒有太多方法,但是它繼承了很多介面,因為介面之間是可以多繼承的。
關於他的父介面,這裡不做多說明,詳情的話請看下子文章(後續更新)。
一看這個類,大家都知道了,我們用的範例全是用這個類去啟動我們的spring的,我們看看他的主要方法:
主要就是去解析xml設定的bean定義將其注入到spring容器中,功能其實跟AnnotationConfigApplicationContext類似,但是卻沒有AnnotationConfigApplicationContext強大,比如不能註冊BeanDefinition。
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;
}
我們可以通過實現bean的後置處理器,來對某一個bean或者所有bean的進行干預,博主只是隨便寫了一個,沒有什麼太大意義。
BeanFactoryPostProcessor表示Bean工廠的後置處理器,其實和BeanPostProcessor類似,BeanPostProcessor是干涉Bean的建立過程,BeanFactoryPostProcessor是干涉BeanFactory的建立過程,我們也可以自定義:
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("加工beanFactory");
}
}
FactoryBean和BeanFactory不是一個東西,大家不要混淆兩個概念,BeanFactory是管理我們注入的bean等,而FactoryBean本身也會被Spring管理,一旦Spring知道我們的bean實現了FactoryBean,那麼會自動呼叫getObject方法獲取我們自己建立的bean,這個bean完完全全交給我們自己建立了,我們可以這樣定義一個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的生命建立週期。細心的朋友會發現,這根我在設定類中寫@bean形式的類有啥區別,現象來講,他倆都可以被建立出來,但是值得一提的是,FactoryBean建立出來的bean是沒走spring定義的bean生命週期的。
Spring啟動時需要掃描指定包路徑下的所有類檔案來獲取需要注入或管理的Bean資訊。然而,並非所有類都是需要的,這時可以使用ASM技術來解析類檔案的後設資料資訊,包括類上的註解資訊和類的基本資訊。ASM技術可以在執行時動態生成和修改Java位元組碼,從而高效地解析類檔案的後設資料資訊,避免了大量的IO操作和類載入,提高了應用的效能。以下是一個簡單的範例:
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);
通過本文的解析,我們大致瞭解了Spring框架中的一些關鍵元件及其用途,這有助於我們在深入理解Spring原始碼過程中建立起一個整體框架。Spring原始碼量很大,要真正理解透徹還需要投入大量時間進行細緻學習和總結。但如果先對一些關鍵元件有一個大致的認識,有助於我們進行鍼對性學習,避免迷失在繁雜的細節中。希望本文能夠對讀者有一定的幫助,更希望讀者在學習Spring原始碼的過程中,不斷總結和提高,並在一定階段有所突破。祝讀者順利!