前言
spring源碼包含很多個模塊,如sping-core,sping-beans,sping-context,spring-aop,spring-web,spring-webmvc,spring-webflux等
在之前研究源碼時,往往都是統(tǒng)一視為spring,而忽略了各個模塊所承擔(dān)的職責(zé),今天決定徹底梳理一下spring的架構(gòu)脈絡(luò),好對spring有個全局的認(rèn)知
架構(gòu)
下面這張圖來源于Spring 4.3.27版本的doc文檔中

圖片有些過時了,大體還是差不多,今天從web開發(fā)角度,由里向外,分析以下幾個較重要的模塊
Core: Beans, Core,Context,AOP
Web: Web, WebMVC,WebFlux
Data Access:JDBC
Boot: Boot的整合和自動配置
spring-core
spring-core這個包是spring通用性代碼的封裝,單獨拿出來并沒有什么作用,一般我們自己開發(fā)項目也會有一個通用的包或模塊,spring-core可看做整個spring架構(gòu)中的通用模塊
spring-beans
從名字可以看出:Beans,即很多的bean,我們常說spring是一個bean容器、一個IOC容器,這其實就是spring-beans中BeanFactory的功勞了,所以spring-beans是spring框架的核心基礎(chǔ)
spring-beans中,把bean的生產(chǎn)者抽象為bean工廠(BeanFactory),bean生產(chǎn)的圖紙抽象為bean定義(BeanDefinition),并實現(xiàn)了一個默認(rèn)的bean工廠:DefaultListableBeanFactory,使用它我們可以注冊一個bean定義并最終獲取到bean,從創(chuàng)建到存儲到銷毀的生命周期都交給了BeanFactory
bean在BeanFactory的存儲方式就是傳說中的三級緩存了,實際上也就是三個map而已
引入依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
bean容器
測試一下bean容器的功能,注冊一個bean定義并獲取
創(chuàng)建一個簡單的User類
public class User {
public void say() {
System.out.println("hello world");
}
}
@Test
public void container() {
// bean工廠
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 注冊用戶bean定義
beanFactory.registerBeanDefinition("user", new RootBeanDefinition(User.class));
// 獲取
User bean = beanFactory.getBean(User.class);
// 調(diào)用方法
bean.say(); // 輸出hello world
}
獲取bean的方式,可以通過注冊時的名字獲取,也可以如例子中的getByType
后置處理器
spring-beans中抽象了可配置的BeanFactory: ConfigurableBeanFactory,這種BeanFactory是支持添加后置處理器的來配置bean的創(chuàng)建步驟的,而DefaultListableBeanFactory也是一種ConfigurableBeanFactory
bean的后置處理有很多種,可以定制不同類型的后置處理器,以便在bean生命周期的不同階段自定義步驟
比如我們可以實現(xiàn)InstantiationAwareBeanPostProcessor(實例化感知后置處理器),在bean的生產(chǎn)過程注入屬性值
public void postProcessor() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 注冊用戶bean定義
beanFactory.registerBeanDefinition("user", new RootBeanDefinition(User.class));
// 注冊汽車的bean定義
beanFactory.registerBeanDefinition("car", new RootBeanDefinition(Car.class));
// 添加后置處理器
beanFactory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() {
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
if (bean instanceof User) { // 給user的bean填充屬性
((User) bean).setCar(beanFactory.getBean(Car.class));
}
return pvs;
}
});
// 獲取bean
User bean = beanFactory.getBean(User.class);
// 調(diào)用屬性的方法
bean.getCar().run(); // running
}
最終完成了Car的bean注入到User的屬性中,可以繼續(xù)優(yōu)化一下這個后置處理器: 寫一個注解,然后檢查某類是否有某個屬性有這個注解,如果有就通過getBeanByType的方式設(shè)置屬性值,這就是我們使用@Autowire的邏輯
而這個后置處理器,spring-beans包中也給我們封裝好了,即AutowiredAnnotationBeanPostProcessor
依賴注入
DefaultListableBeanFactory本身支持使用設(shè)置AutowireMode的方式完成自動裝配,但這種方式粒度太大,一般我們需要根據(jù)用戶的配置按需自動注入,這種情況就需要使用后置處理器,spring-beans包中已為我們封裝好了: AutowiredAnnotationBeanPostProcessor,使用它我們可以用注解@Autowired來配置屬性自動注入
@Autowired
private Car car;
@Test
public void autowiredAnnotation() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 注冊用戶bean定義
beanFactory.registerBeanDefinition("user", new RootBeanDefinition(User.class));
// 注冊汽車的bean定義
beanFactory.registerBeanDefinition("car", new RootBeanDefinition(Car.class));
// 添加注解方式自動裝配后置處理
AutowiredAnnotationBeanPostProcessor postProcessor = new AutowiredAnnotationBeanPostProcessor();
postProcessor.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(postProcessor);
// 獲取bean
User bean = beanFactory.getBean(User.class);
// 調(diào)用屬性的方法
bean.getCar().run(); // running
}
FactoryBean
bean工廠DefaultListableBeanFactory還支持FactoryBean,使用這種方式BeanFactory只作為一個容器存儲,而實際創(chuàng)建的過程用戶完全自定義,試一下
定義一個生產(chǎn)Car的工廠,實現(xiàn)FactoryBean
public class CarFactory implements FactoryBean<Car> {
@Override
public Car getObject() throws Exception { // 生產(chǎn)Car
return new Car();
}
@Override
public Class<?> getObjectType() { // 生產(chǎn)類型
return Car.class;
}
}
測試一下
public void factoryBean() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
RootBeanDefinition carFactoryBeanDefinition = new RootBeanDefinition(CarFactory.class);
// 注冊工廠bean定義
beanFactory.registerBeanDefinition("carFactory", carFactoryBeanDefinition);
Car bean = beanFactory.getBean(Car.class);
bean.run(); // running
}
小結(jié)
spring-beans包是spring框架的基礎(chǔ),提供了BeanFactory,其中一個重要的實現(xiàn)即DefaultListableBeanFactory,使用它我們可以實現(xiàn)一個bean容器,通過后置處理器或FactoryBean的方式我們可以控制特殊bean的自定義生產(chǎn)過程,并且spring-beans內(nèi)部寫好了一個注解方式的依賴注入的后置處理器,使用它可以方便實現(xiàn)依賴注入
spring-aop
spring-aop是面向切面編程的支持模塊,相比于spring-beans是一個基礎(chǔ)模塊,spring-aop則是一個可選模塊,如果不需要面向切面編程,完全可以不使用
spring-aop基于spring-beans,它主要提供了一系列特殊的BeanFactory后置處理器,使用這種特殊后置處理器,就可以很輕松實現(xiàn)面向切面編程,例如:
- AbstractAutoProxyCreator
- AbstractAdvisorAutoProxyCreator
- AnnotationAwareAspectJAutoProxyCreator
AbstractAutoProxyCreator
比如還是上面的例子,我們希望給User和Car的方法執(zhí)行前都打印一下方法名,使用AOP可以如下處理:
加入aop依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
此時我們不需要修改User或Car的方法,只需要實現(xiàn)一個AOP創(chuàng)建器即可,即實現(xiàn)AbstractAutoProxyCreator,他就是spring-aop模塊提供的特殊的專做AOP的后置處理器
@Test
public void autoProxyCreator() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 注冊用戶bean定義
beanFactory.registerBeanDefinition("user", new RootBeanDefinition(User.class));
// 添加aop攔截后置處理
beanFactory.addBeanPostProcessor(new AbstractAutoProxyCreator() {
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException {
return new Object[]{
(MethodBeforeAdvice) (method, args, target) -> {
System.out.println("the method is " + method.getName());
}
};
}
});
// 調(diào)用User方法
beanFactory.getBean(User.class).say();
}
攔截方式即方法執(zhí)行前打印一下方法名, 輸出如下

AnnotationAwareAspectJAutoProxyCreator
同時,spring-aop還支持AspectJ語法,對應(yīng)的后置處理器是AnnotationAwareAspectJAutoProxyCreator
使用這種后置處理器,就可以在BeanFactory中查找按AspectJ語法寫出的攔截器,并轉(zhuǎn)換為spring-aop的Advisor以進(jìn)行方法攔截,當(dāng)然需要引入AspectJ的相關(guān)依賴
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
按AspectJ語法寫一個攔截器,后續(xù)加入到bean容器
@Aspect
public class ShowMethodAspect {
@Pointcut("execution(* me.pq.spring.beans.*.*(..))")
public void showMethod() {
}
@Before("showMethod()")
public void before(JoinPoint joinPoint) {
System.out.println(joinPoint); // 打印下方法即可
}
}
攔截器加入到bean容器,并注冊該后置處理
@Test
public void annotationAwareAspectJAutoProxyCreator() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 注冊用戶bean定義
beanFactory.registerBeanDefinition("user", new RootBeanDefinition(User.class));
// 注冊AspectJ語法攔截器至bean容器
beanFactory.registerBeanDefinition("showMethodAspect", new RootBeanDefinition(ShowMethodAspect.class));
// 初始化AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator aopCreator = new AnnotationAwareAspectJAutoProxyCreator();
// 因為實現(xiàn)方式是取bean容器查找,所以必須指定beanFactory
aopCreator.setBeanFactory(beanFactory);
// 添加到后置處理
beanFactory.addBeanPostProcessor(aopCreator);
// 調(diào)用User方法
beanFactory.getBean(User.class).say();
}
最終輸出如下

小結(jié)
spring-aop就是給spring-beans提供了一系列的aop相關(guān)功能的后置處理器
spring-context
有了spring-beans,我們可以實現(xiàn)一個IOC容器,有了spring-aop,我們可以在IOC的基礎(chǔ)上實現(xiàn)AOP,那么spring-context模塊又有什么用?
spring-context抽象出了ApplicationContext, 代表應(yīng)用上下文,相比spring-beans是一個bean的生命周期管理的單純工具,spring-context是管理整個spring應(yīng)用,并同時維護(hù)著內(nèi)部的BeanFactory,承擔(dān)的責(zé)任必然更多,比如對事件的支持和國際化的支持,最重要的是我們不需要手動注冊bean定義了,也不需要手動添加后置處理器了
總之,有了ApplicationContext,我們不需要再直接和BeanFactory打交道,這個工作交給了ApplicationContext,我們只需用更簡易的方式操作ApplicationContext即可
ApplicationContext的實現(xiàn)也有很多,最具代表性的是AnnotationConfigApplicationContext,即基于注解的ApplicationContext
自動注冊bean定義
使用AnnotationConfigApplicationContext,不需要再去創(chuàng)建BeanFactory,ApplicationContext初始化時自動創(chuàng)建
也不需要注冊bean定義,spring-context中提供了@ComponentScan和@Component注解,AnnotationConfigApplicationContext初始化時,會把@ComponentScan指定包路徑下的帶@Component的類自動生成bean定義并注冊到內(nèi)部的BeanFactory
@Component
public class User {
public void say() {System.out.println("hello world");}
}
@Test
public void context() {
ApplicationContext context = new AnnotationConfigApplicationContext(ContextTest.class);
User bean = context.getBean(User.class);
bean.say();
}
依賴注入
上面使用BeanFactory添加AutowiredAnnotationBeanPostProcessor后置處理器,即可識別@Autowired注解完成自動注入
同樣使用AnnotationConfigApplicationContext也支持@Autowired注解的依賴注入方式,原因就是:AnnotationConfigApplicationContext在初始化時,給內(nèi)部的beanFactory加入了AutowiredAnnotationBeanPostProcessor后置處理器
public void autowire() {
ApplicationContext context = new AnnotationConfigApplicationContext(ContextTest.class);
User bean = context.getBean(User.class);
bean.getCar().run();
}
當(dāng)然,除了識別@Autowired注解的后置處理器,AC初始化時還給bean工廠自動添加了其它的后置處理器,比如識別@Required注解的處理器
FactoryBean
使用AnnotationConfigApplicationContext當(dāng)然一樣支持FactoryBean,只要@Component修飾的類實現(xiàn)了FactoryBean接口即可
AnnotationConfigApplicationContext同時還擴(kuò)展了一種新的工廠bean創(chuàng)建模式,即常用的@Configuration+@Bean注解
BeanFactory后置處理器
spring-context抽象出了一種新的后置處理器,即BeanFactoryPostProcessor(實際在spring-beans模塊中)
相比于BeanPostProcessor是在bean的創(chuàng)建過程中添加自定義操作,BeanFactoryPostProcessor一般是在BeanFactory初始化之后的自定義操作
這個很好理解,有了ApplicationContext一般情況下不需要直接操作BeanFactory,但難免會有一些特殊情況,用戶就要按照自己的邏輯給BeanFactory中加入一些bean定義、bean后置處理等(比如Mybaits),有了BeanFactoryPostProcessor我們就可以在AC內(nèi)部初始化BeanFactory后加入自己的一些自定義操作
實際上,上面AnnotationConfigApplicationContext解析@ComponentScan、@Component、@Bean,包括常用的@Import注解都是AnnotationConfigApplicationContext初始化時自己給自己加入的一個特殊的BeanFactory后置處理器來實現(xiàn)的,即ConfigurationClassPostProcessor
AOP
spring-context是直接依賴spring-aop的,所以自然也有了AOP的功能,但之前也說過AOP的功能是可選的,所以spring-context提供了EnableAspectJAutoProxy,使用了這個注解,spring-context初始化時才會給beanFactory加入上面提到的AnnotationAwareAspectJAutoProxyCreator后置處理器
總之,使用了EnableAspectJAutoProxy注解,spring-context就擁有了AOP的能力,我們只要給實現(xiàn)了@Aspect的攔截器加上@Component注解讓它進(jìn)入bean容器即可實現(xiàn)方法攔截
@Aspect
@Component
public class ShowMethodAspect {
小結(jié)
spring-context整合了spring-beans和spring-aop,讓我們不需要手動注冊bean定義,也不需要手動添加后置處理器
使用spring-context時,不管是普通的bean還是后置處理器我們只需指定其為bean即可(比如注解@Component),spring-context會自動把實現(xiàn)了后置處理的特殊bean從容器中取出作為后置處理器執(zhí)行
在一文通透spring的初始化對上面的具體實現(xiàn)有詳細(xì)介紹
spring-jdbc
這個基本都知道,用于操作數(shù)據(jù)庫的一個好用的JDBC工具
模塊中提供了一個JdbcTemplate,使用它可以非常輕松完成數(shù)據(jù)庫操作,而它只是jdbc的一個封裝,想連接數(shù)據(jù)庫對應(yīng)的驅(qū)動是少不了的,比如mysql
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
此時使用JdbcTemplate,即可操作數(shù)據(jù)庫
@Test
public void jdbc() {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(new SingleConnectionDataSource("jdbc:mysql://{url}", "{username}", "{password}", false));
List<Map<String, Object>> result = jdbcTemplate.query("select * from xxx", new ColumnMapRowMapper());
System.out.println(result);
}
spring-tx
提到j(luò)dbc就要考慮事務(wù),spring-tx是專門做事務(wù)支持的,所以spring-jdbc也需要依賴spring-tx模塊
spring-web
有了spring-context、spring-beans、spring-aop,我們就有了一個IOC和AOP的容器
有了spring-jdbc,我們可以去操作數(shù)據(jù)庫
但做web開發(fā),還需要處理http通訊,包括根據(jù)請求路徑分發(fā)服務(wù),這時就需要spring-web模塊了
而spring-web只是web開發(fā)中一些通用類的封裝,實際要做一個web服務(wù),還是直接用spring-webmvc
關(guān)于二者的詳細(xì)區(qū)別,可以移步spring-web與spring-webmvc
spring-webmvc
這個再熟悉不過了,是一個mvc的框架,也支持restful協(xié)議
spring-webmvc基于于spring-web(web通用模塊)、spring-context(spring上下文),可以運行在servlet容器如tomcat上
spring-webmvc單獨使用一般就是老套的xml配置,打war包,最終運行在類似tomcat上
spring-boot
這大家都在用,就不細(xì)說了
有了它,比如寫web項目,不需要再考慮spring架構(gòu)各模塊的作用了,也不需要再去配合tomcat使用了,只要引入spring-boot-starter-web就引入了springmvc和嵌入式的tomcat,該寫的復(fù)雜配置boot都寫好了,直接run就行了
spring-boot還有一個超好用的自動配置機(jī)制:springboot之AutoConfiguration
spring-webflux
響應(yīng)式的web服務(wù),基于spring-web,諷刺的是spring-web的很多通用代碼在響應(yīng)式領(lǐng)域并不適用,因此spring-webflux對spring-web的依賴相對比較薄弱
spring-webflux不僅支持運行在傳統(tǒng)Servlet容器,還支持運行在Netty上,比如spring-boot-starter-webflux就引用spring-webflux并默認(rèn)運行在Netty上
spring-webflux的詳細(xì)介紹:響應(yīng)式編程之WebFlux