Spring源码阅读目录
第一部分——IOC篇
第一章 Spring之最熟悉的陌生人——IOC
第二章 Spring之假如让你来写IOC容器——加载资源篇
第三章 Spring之假如让你来写IOC容器——解析配置文件篇
第四章 Spring之假如让你来写IOC容器——XML配置文件篇
第五章 Spring之假如让你来写IOC容器——BeanFactory和FactoryBean
第六章 Spring之假如让你来写IOC容器——Scope和属性填充
第七章 Spring之假如让你来写IOC容器——属性填充特别篇:SpEL表达式
第八章 Spring之假如让你来写IOC容器——拓展篇
第九章 Spring之源码阅读——环境搭建篇
第十章 Spring之源码阅读——IOC篇
第二部分——AOP篇
第十一章 Spring之不太熟的熟人——AOP
第十二章 Spring之不得不了解的内容——概念篇
第十三章 Spring之假如让你来写AOP——AOP联盟篇
第十四章 Spring之假如让你来写AOP——雏形篇
第十五章 Spring之假如让你来写AOP——Joinpoint(连接点)篇
第十六章 Spring之假如让你来写AOP——Pointcut(切点)篇
第十七章 Spring之假如让你来写AOP——Advice(通知)上篇
第十八章 Spring之假如让你来写AOP——Advice(通知)下篇
第十九章 Spring之假如让你来写AOP——番外篇:Spring早期设计
第二十章 Spring之假如让你来写AOP——Aspect(切面)篇
第二十一章 Spring之假如让你来写AOP——Weaver(织入器)篇
第二十二章 Spring之假如让你来写AOP——Target Object(目标对象)篇
第二十三章 Spring之假如让你来写AOP——融入IOC容器篇
第二十四章 Spring之源码阅读——AOP篇
第三部分——事务篇
第二十五章 Spring之曾经的老朋友——事务
第二十六章 Spring之假如让你来写事务——初稿篇
第二十七章 Spring之假如让你来写事务——铁三角篇
第二十八章 Spring之假如让你来写事务——属性篇
第二十九章 Spring之假如让你来写事务——状态篇
第三十章 Spring之假如让你来写事务——管理篇
第三十一章 Spring之假如让你来写事务——融入IOC容器篇
第三十二章 Spring之源码阅读——事务篇
第四部分——MVC篇
第三十三章 Spring之梦开始的地方——MVC
第三十四章 Spring之假如让你来写MVC——草图篇
第三十五章 Spring之假如让你来写MVC——映射器篇
第三十六章 Spring之假如让你来写MVC——拦截器篇
第三十七章 Spring之假如让你来写MVC——控制器篇
第三十八章 Spring之假如让你来写MVC——适配器篇
第三十九章 Spring之假如让你来写MVC——番外篇:类型转换
第四十章 Spring之假如让你来写MVC——ModelAndView篇
第四十一章 Spring之假如让你来写MVC——番外篇:数据绑定
第四十二章 Spring之假如让你来写MVC——视图篇
第四十三章 Spring之假如让你来写MVC——上传文件篇
第四十四章 Spring之假如让你来写MVC——异常处理器篇
第四十五章 Spring之假如让你来写MVC——国际化篇
第四十六章 Spring之假如让你来写MVC——主题解析器篇
第四十七章 Spring之假如让你来写MVC——闪存管理器篇
第四十八章 Spring之假如让你来写MVC——请求映射视图篇
第四十九章 Spring之假如让你来写MVC——番外篇:属性操作
第五十章 Spring之假如让你来写MVC——融入IOC容器篇
第五十一章 Spring之源码阅读——MVC篇
第五部分——Boot篇
第五十二章 Spring之再进一步——Boot
第五十三章 Spring之假如让你来写Boot——环境篇
第五十四章 Spring之假如让你来写Boot——注解篇(上)
第五十五章 Spring之假如让你来写Boot——注解篇(下)
第五十六章 Spring之假如让你来写Boot——SPI篇
第五十七章 Spring之假如让你来写Boot——配置文件篇(上)
第五十八章 Spring之假如让你来写Boot——配置文件篇(下)
第五十九章 Spring之假如让你来写Boot——番外篇:再谈Bean定义
第六十章 Spring之假如让你来写Boot——自动装配篇
第六十一章 Spring之假如让你来写Boot——番外篇:杂谈Starter
第六十二章 Spring之假如让你来写Boot——番外篇:重构BeanFactory
第六十三章 Spring之假如让你来写Boot——番外篇:再谈ApplicationContext
第六十四章 Spring之假如让你来写Boot——内嵌Web容器篇
第六十五章 Spring之假如让你来写Boot——Main方法启动篇
第六十六章 Spring之最终章——结语篇
文章目录
前言
对于Spring一直都是既熟悉又陌生,说对它熟悉吧,平时用用没啥问题,但面试的时候被问的一脸懵逼,就很尴尬,都不好意思在简历上写着熟悉Spring了
所以决定花点时间研究研究Spring的源码。主要参考的书籍是:《Spring源码深度解析(第2版)》、《Spring揭秘》、《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》
书接上回,在上篇 第四章 Spring源码阅读之假如让你来写IOC容器——XML配置文件篇 已经实现了XML校验、解析自定义XML标签,并且项目已经顺利上线了。接下来看看上线之后还会遇到什么问题吧
尝试动手写IOC容器
出场人物:A君(苦逼的开发)、老大(项目经理)
背景:老大要求A君在一周内开发个简单的IOC容器
前情提要:在A君孜孜不倦的努力下,提供了自定义XML标签,项目终于上线了。项目上线后,A君无事一身轻,每天抖腿等下班。。。
第八版 抽取BeanFactory接口
每天摸鱼,A君多少闲得发慌。闲来无事又把之前的代码看了一遍,发现了些许问题:按照老大之前的要求,凡事都要先提取接口,而SpringImitation显然不满足需求
闲着也是闲着,A君决定优化一波。A君提取出了BeanFactory接口,BeanFactory,顾名思义,是用来专门获取bean对象的工厂接口,其代码如下:
public interface BeanFactory {
<T> T getBean(String beanName, Class<T> clazz);
Object getBean(String name);
}
实现类还是SpringImitation类,基本不用改动,改动如下:
完整代码:
import com.hqd.ch03.v8.config.BeanDefinition;
import com.hqd.ch03.v8.config.MutablePropertyValues;
import com.hqd.ch03.v8.factory.BeanFactory;
import com.hqd.ch03.v8.io.ResourceLoader;
import com.hqd.ch03.v8.io.support.DefaultResourceLoader;
import com.hqd.ch03.v8.registry.BeanDefinitionRegistry;
import com.hqd.ch03.v8.registry.SimpleBeanDefinitionRegistry;
import org.apache.commons.beanutils.BeanUtils;
public abstract class SpringImitationV8 implements BeanFactory {
protected BeanDefinitionRegistry beanDefinitionRegistry = new SimpleBeanDefinitionRegistry();
/**
* 资源加载器
*/
protected ResourceLoader resourceLoader = new DefaultResourceLoader();
private void initBean(Object bean, BeanDefinition bd) {
try {
MutablePropertyValues properties = bd.getProperties();
properties.getProperties().keySet().forEach(name -> {
String value = properties.getValue(name);
try {
BeanUtils.setProperty(bean, name, value);
} catch (Exception e) {
e.printStackTrace();
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private Object createBean(BeanDefinition bd) {
try {
String beanClass = bd.getBeanClass();
Object o = Class.forName(beanClass).getConstructor().newInstance();
initBean(o, bd);
return o;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public <T> T getBean(String beanName, Class<T> clazz) {
BeanDefinition bd = beanDefinitionRegistry.getBeanDefinition(beanName);
return (T) createBean(bd);
}
@Override
public Object getBean(String name) {
BeanDefinition bd = beanDefinitionRegistry.getBeanDefinition(name);
return createBean(bd);
}
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
这么简单的改动,A君自信满满,连简单的测试都不想测试,直接上版本,淦就完事了
第九版 抽取FactoryBean接口
快乐的时光总是短暂的,就在A君志得意满的时候,老大又找到A君,诉说了用户的新需求:A君,用户不满足于标签配置,他们有非常特殊的类,通过标签配置太过繁琐了,希望能通过代码实现
“用户啊,总能整出点奇奇怪怪的要求,想要方便又要特殊”,到了现在,A君不得不感叹需求的变化多端,用户的想法天马行空
面对新的需求,A君不经又一阵挠头。和之前自定义标签有些类似,但又不完全相同。想要个性化,必然存在接口,而后用户去具体实现。至于配置文件嘛,这时候容器已经可以加载bean对象了,就把用户要自定义的bean特殊处理下就可以了,用不着像自定义标签一样,再另外定义配置文件了
有了思路后,A君准备定义接口,接口起名为FactoryBean。所谓FactoryBean,工厂bean,用来创建bean对象的特殊bean。有点拗口,其实就是一个特殊的bean,一个拥有创建bean对象能力的bean。接口定义好之后,由于用户有可能用FactoryBean获取新的bean,也有可能单纯的想获取 FactoryBean对象,所以A君又添加&符号,有&符号则是获取FactoryBean本身,没有则是用FactoryBean获取新的bean。FactoryBean接口代码如下:
public interface FactoryBean<T> {
Class<?> getObjectType();
T getObject();
}
SpringImitation类需要做出相应修改,也简单,只需要对传入的beanNam过滤掉&符号,创建Bean对象后,判断是不是FactoryBean的实现类即可,改造如下:
transformedBeanName方法如下:
getObjectForBeanInstance方法如下:
完整代码:
import com.hqd.ch03.v9.config.BeanDefinition;
import com.hqd.ch03.v9.config.MutablePropertyValues;
import com.hqd.ch03.v9.factory.BeanFactory;
import com.hqd.ch03.v9.factory.FactoryBean;
import com.hqd.ch03.v9.io.ResourceLoader;
import com.hqd.ch03.v9.io.support.DefaultResourceLoader;
import com.hqd.ch03.v9.registry.BeanDefinitionRegistry;
import com.hqd.ch03.v9.registry.SimpleBeanDefinitionRegistry;
import org.apache.commons.beanutils.BeanUtils;
public abstract class SpringImitationV9 implements BeanFactory {
protected BeanDefinitionRegistry beanDefinitionRegistry = new SimpleBeanDefinitionRegistry();
/**
* 资源加载器
*/
protected ResourceLoader resourceLoader = new DefaultResourceLoader();
public static boolean isFactoryDereference(String name) {
return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}
/**
* 处理传入的name,去除&开头
*
* @param name
* @return
*/
protected String transformedBeanName(String name) {
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
String beanName = name;
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
}
/**
* 区分正常bean还是FactoryBean
*
* @param obj
* @param name
* @param beanName
* @param bd
* @return
*/
protected Object getObjectForBeanInstance(Object obj, String name, String beanName, BeanDefinition bd) {
if (isFactoryDereference(name)) {
if (!(obj instanceof FactoryBean)) {
throw new RuntimeException(String.format("%s 未实现FactoryBean接口", beanName));
}
return obj;
}
if (obj instanceof FactoryBean) {
return ((FactoryBean) obj).getObject();
}
return obj;
}
private void initBean(Object bean, BeanDefinition bd) {
try {
MutablePropertyValues properties = bd.getProperties();
properties.getProperties().keySet().forEach(name -> {
String value = properties.getValue(name);
try {
BeanUtils.setProperty(bean, name, value);
} catch (Exception e) {
e.printStackTrace();
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private Object createBean(BeanDefinition bd) {
try {
String beanClass = bd.getBeanClass();
Object o = Class.forName(beanClass).getConstructor().newInstance();
initBean(o, bd);
return o;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public <T> T getBean(String name, Class<T> clazz) {
return (T) doGetBean(name);
}
@Override
public Object getBean(String name) {
return doGetBean(name);
}
protected Object doGetBean(String name) {
String beanName = transformedBeanName(name);
BeanDefinition bd = beanDefinitionRegistry.getBeanDefinition(beanName);
Object bean = createBean(bd);
bean = getObjectForBeanInstance(bean, name, beanName, bd);
return bean;
}
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
这个还是有点改动量的,A君不能像刚才那般自信了,于是,A君准备开始测试了,先定义个UserFactoryBean作为FactoryBean的实现类,代码如下:
import com.hqd.ch03.v9.factory.FactoryBean;
public class UserFactoryBean implements FactoryBean<User> {
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public User getObject() {
User user = new User();
user.setAge(100);
user.setName("李四");
return user;
}
@Override
public String toString() {
return "我是自定义FactoryBean";
}
}
再在bean.xml中添加相关定义,如下:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.hqd.ch03.bean.User">
<property name="name" value="法外狂徒-张三"/>
<property name="age" value="14"/>
</bean>
<bean id="factoryBean" class="com.hqd.ch03.bean.UserFactoryBean"/>
</beans>
最后,在写上测试代码,如下:
/**
* 抽取FactoryBean
*/
@Test
public void v9() {
System.out.println("############# 第九版:抽取FactoryBean #############");
SpringImitationV9 beanFactory = new SpringImitationV9Xml("classpath:v9/bean.xml");
User user = beanFactory.getBean("user", User.class);
System.out.println("加载标签对象:" + user);
Object factoryBean = beanFactory.getBean("factoryBean");
System.out.println("FactoryBean创建对象:" + factoryBean);
Object factory = beanFactory.getBean("&factoryBean");
System.out.println("FactoryBean对象:" + factory);
}
测试结果没出什么意外,如下:
对于FactoryBean的改造总算告一段落了,A君松了口气,总算可以继续摸鱼了
总结
正所谓树欲静而风不止,欲知后事如何,请看下回分解(✪ω✪)