手撸spring源码分析IOC实现原理
文章出处:https://github.com/fuzhengwei/small-spring
根据小付哥的手撸spring核心源码一步步学习出来的结果收货总结。
BeanDefinition :Object对象。
public class BeanDefinition {
private Object bean;
public BeanDefinition(Object bean) {
this.bean = bean;
}
public Object getBean() {
return bean;
}
}
beanFactory:容器工厂对象。一个map集合用于存储实例对象。
为什么使用map集合进行存储? ArrayList、linkedList、HashSet等,但在 Spring Bean 容器的场景下, 我们需要一种可以用于存放和名称索引式的数据结构,所以选择 HashMap 是最合适不过的。
public class BeanFactory {
private Map beanDefinitionMap = new ConcurrentHashMap<>();
public Object getBean(String name) {
return beanDefinitionMap.get(name).getBean();
}
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
beanDefinitionMap.put(name, beanDefinition);
}
}
public class UserService {
public void queryUserInfo(){
System.out.println("111");
}
public UserService(){
System.out.println("默认无参构造创造");
}
}
@Test
public void test_BeanFactory(){
// 1.初始化 BeanFactory
BeanFactory beanFactory = new BeanFactory();
// 2.注册 bean
BeanDefinition beanDefinition = new BeanDefinition(new UserService());
beanFactory.registerBeanDefinition("userService", beanDefinition);
// 3.获取 bean
UserService userService = (UserService) beanFactory.getBean("userService");
userService.queryUserInfo();
}
spring初显身手,运用设计模式,实现 Bean 的定义、注册、获取
本章将 Spring Bean 容器完善起来,首先非常重要的一点是在 Bean 注册的时候只注册一个类信息,而不会直接把实例化信息注册到 Spring 容器中。那么就需要修改 BeanDefinition 中的属性 Object 为 Class,接下来在需要做的就是在获取 Bean 对象时需要处理 Bean 对象的实例化操作以及判断当前单例对象在容器中是否已经缓存起来了
public class BeanDefinition {
private Class beanClass;
public BeanDefinition(Class beanClass) {
this.beanClass = beanClass;
}
// ...get/set
}
单例注册接口定义和实现
//获取单例对象的接口
public interface SingletonBeanRegistry {
Object getSingleton(String beanName);
}
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
private Map singletonObjects = new HashMap<>();
@Override
public Object getSingleton(String beanName) {
return singletonObjects.get(beanName);
}
protected void addSingleton(String beanName, Object singletonObject) {
singletonObjects.put(beanName, singletonObject);
}
}
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
@Override
public Object getBean(String name) throws BeansException {
Object bean = getSingleton(name);
if (bean != null) {
return bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return createBean(name, beanDefinition);
}
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;
}
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
Object bean = null;
try {
bean = beanDefinition.getBeanClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new BeansException("Instantiation of bean failed", e);
}
addSingleton(beanName, bean);
return bean;
}
}
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry {
private Map beanDefinitionMap = new HashMap<>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
beanDefinitionMap.put(beanName, beanDefinition);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition == null) throw new BeansException("No bean named '" + beanName + "' is defined");
return beanDefinition;
}
}
@Test
public void test_BeanFactory(){
// 1.初始化 BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 2.注册 bean
BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
beanFactory.registerBeanDefinition("userService", beanDefinition);
// 3.第一次获取 bean
UserService userService = (UserService) beanFactory.getBean("userService");
userService.queryUserInfo();
// 4.第二次获取 bean from Singleton
UserService userService_singleton = (UserService) beanFactory.getBean("userService");
userService_singleton.queryUserInfo();
}
执行流程分析
实例化一个容器
需要实例化对象的class,然后注册到容器中
注意:默认调用无参构造进行创建,如果重新了有参构造后会实例失败。
基于Cglib实现含构造函数的类实例化策略public interface BeanFactory {
Object getBean(String name) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
}
public interface InstantiationStrategy {
Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException;
}
基于jdk的实例化
public class SimpleInstantiationStrategy implements InstantiationStrategy {
@Override
public Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException {
Class clazz = beanDefinition.getBeanClass();
try {
if (null != ctor) {
return clazz.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args);
} else {
return clazz.getDeclaredConstructor().newInstance();
}
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new BeansException("Failed to instantiate [" + clazz.getName() + "]", e);
}
}
}
基于Cglib的实例化
public class CglibSubclassingInstantiationStrategy implements InstantiationStrategy {
@Override
public Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanDefinition.getBeanClass());
enhancer.setCallback(new NoOp() {
@Override
public int hashCode() {
return super.hashCode();
}
});
if (null == ctor) return enhancer.create();
return enhancer.create(ctor.getParameterTypes(), args);
}
}
如果实例的:采用cglib
对象属性值填充 从Spring.xml解析和注册Bean对象优化从配置文件中实例化bean
step1:实例化beanFactory。
step2:
会判断当前传入的location是属于哪些类型的,classpathResource还是fileSystemResource还是Url 判断方式如下图
根据返回的Resource转为输入流,
把当前输入流转为xml对象进行读取属性赋值操作后 放入到DefaultListableBeanFactory中的private Map
step3:如何实例化:
先冲缓存中根据key(bean的name名称)取,如果没有则创建后添加到缓存中并返回,如果有直接返回。
实现应用上下文,自动识别、资源加载、扩展机制 BeanFactoryPostProcessor(bean的定义信息加载之后,bean实例化之前执行改接口实现方法,用于BeanDefinition的修改) BeanPostProcessor(实例化前的提前处理:准确来说是提前于bean实例化,利用在实例化之前检查是否存在合适的BeanPostProcessor对象,去拦截某些需要被处理的bean提前完成bean的实例化过程,不会去调用init方法,也没有数据的填充)流程分析图:
准备实体:
public class UserService {
private String uId;
private String company;
private String location;
private UserDao userDao;
//setter and getter
}
MyBeanFactoryPostProcessor:用于测试BeanFactoryPostProcessor
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");
PropertyValues propertyValues = beanDefinition.getPropertyValues();
propertyValues.addPropertyValue(new PropertyValue("company", "改为:字节跳动"));
}
}
MyBeanPostProcessor:用于测试BeanPostProcessor
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
UserService userService = (UserService) bean;
userService.setLocation("改为:北京");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
准备就绪开干:
测试方法:
@Test
public void test_xml() {
// 1.初始化 BeanFactory
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:springPostProcessor.xml");
// 2. 获取Bean对象调用方法
UserService userService = applicationContext.getBean("userService", UserService.class);
String result = userService.queryUserInfo();
System.out.println("测试结果:" + result);
}
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(“classpath:springPostProcessor.xml”)
- 装载所有的Bean对象。
- 具体流程如下图所示
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
super(registry, resourceLoader);
}
@Override
public void loadBeanDefinitions(Resource resource) throws BeansException {
try {
try (InputStream inputStream = resource.getInputStream()) {
doLoadBeanDefinitions(inputStream);
}
} catch (IOException | ClassNotFoundException e) {
throw new BeansException("IOException parsing XML document from " + resource, e);
}
}
@Override
public void loadBeanDefinitions(Resource... resources) throws BeansException {
for (Resource resource : resources) {
loadBeanDefinitions(resource);
}
}
@Override
public void loadBeanDefinitions(String location) throws BeansException {
ResourceLoader resourceLoader = getResourceLoader();
Resource resource = resourceLoader.getResource(location);
loadBeanDefinitions(resource);
}
@Override
public void loadBeanDefinitions(String... locations) throws BeansException {
for (String location : locations) {
loadBeanDefinitions(location);
}
}
protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {
document doc = XmlUtil.readXML(inputStream);
Element root = doc.getdocumentElement();
NodeList childNodes = root.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
// 判断元素
if (!(childNodes.item(i) instanceof Element)) continue;
// 判断对象
if (!"bean".equals(childNodes.item(i).getNodeName())) continue;
// 解析标签
Element bean = (Element) childNodes.item(i);
String id = bean.getAttribute("id");
String name = bean.getAttribute("name");
String className = bean.getAttribute("class");
// 获取 Class,方便获取类中的名称
Class> clazz = Class.forName(className);
// 优先级 id > name
String beanName = StrUtil.isNotEmpty(id) ? id : name;
if (StrUtil.isEmpty(beanName)) {
beanName = StrUtil.lowerFirst(clazz.getSimpleName());
}
// 定义Bean
BeanDefinition beanDefinition = new BeanDefinition(clazz);
// 读取属性并填充
for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
if (!(bean.getChildNodes().item(j) instanceof Element)) continue;
if (!"property".equals(bean.getChildNodes().item(j).getNodeName())) continue;
// 解析标签:property
Element property = (Element) bean.getChildNodes().item(j);
String attrName = property.getAttribute("name");
String attrValue = property.getAttribute("value");
String attrRef = property.getAttribute("ref");
// 获取属性值:引入对象、值对象
Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;
// 创建属性信息
PropertyValue propertyValue = new PropertyValue(attrName, value);
beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
}
if (getRegistry().containsBeanDefinition(beanName)) {
throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
}
// 注册 BeanDefinition
getRegistry().registerBeanDefinition(beanName, beanDefinition);
}
}
}
注册 BeanDefinition: getRegistry().registerBeanDefinition(beanName, beanDefinition);
以上操作完成bean的加载和注册
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
上图只是拿到了banFactory中有哪些是BeanPostProcessor的子类。并不会立即处理。
beanFactory.preInstantiateSingletons(); 实例化对象
到此完成了BeanDefinition的的修改。完成了BeanPostProcessor和BeanFactoryPostProcessor的对bean的不同时机的修改操作!
1.整体流程说明:根据传入的路径。判断出具体的解析方式是classpath,url,FileSystem。然后读取配置中的Bean定义信息。完成对BeanDefinition第一次的初始化操作并放入DefaultListableBeanFactory中的beanDefinitionMap中去。
2.获取到DefaultListableBeanFactory对象。(这个对象包含bean的定义信息)
3.执行BeanFactoryPostProcessor。说白了就拿到实现了BeanFactoryPostProcessor接口的类,然后拿到需要修改的属性。放入List propertyValueList = new ArrayList<>();集合中去。
4,在实例化bean之前提前拿到实现了BeanPostProcessor的类。然后放入AbstractBeanFactory 中的List beanPostProcessors = new ArrayList();集合中去。
5.创建实例:实例化对象(cglib或jdk),给 Bean 填充属性时执行List propertyValueList = new ArrayList<>();循环然后覆盖。执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法。
龙行有风,向虚拟机注册钩子,实现Bean对象的初始化和销毁方法 定义初始化和销毁方法的接口(init-method、destroy-method)加入bean的生命周期
A 创建时需要依赖 B 创建,而B 的创建又依赖于 A 创建,就这样死循环了
分类:
一级缓存解决方式:
package cn.bugstack.springframework.test;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class CircleTest {
private final static Map singletonObjects = new ConcurrentHashMap<>(256);
public static void main(String[] args) throws Exception {
System.out.println(getBean(B.class).getA());
System.out.println(getBean(A.class).getB());
}
private static T getBean(Class beanClass) throws Exception {
String beanName = beanClass.getSimpleName().toLowerCase();
if (singletonObjects.containsKey(beanName)) {
return (T) singletonObjects.get(beanName);
}
// 实例化对象入缓存
Object obj = beanClass.newInstance();
singletonObjects.put(beanName, obj);
// 属性填充补全对象
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Class> fieldClass = field.getType();
String fieldBeanName = fieldClass.getSimpleName().toLowerCase();
field.set(obj, singletonObjects.containsKey(fieldBeanName) ? singletonObjects.get(fieldBeanName) : getBean(fieldClass));
field.setAccessible(false);
}
return (T) obj;
}
}
class A {
private B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
class B {
private A a;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
Spring BeanFactory和FactoryBean的区别
| BeanFactory | 提供了一系列的获取bean对象的方法。Object getBean(String name), T getBean(String name, Class requiredType) |
|---|---|
| FactoryBean | 实现了 FactoryBean 接口的类有能力改变 bean,具有代理作用. |
| BeanFactoryPostProcessor | 它的实现类可以在当前BeanFactory初始化(spring容器加载bean定义文件)后,bean实例化之前修改bean的定义属性,达到影响之后实例化bean的效果 |
|---|---|
| BeanPostProcessor | postProcessBeforeInitialization(Object bean, String beanName)和postProcessAfterInitialization(Object bean, String beanName)方法 作用:BeanPostProcessor能在spring容器实例化bean之后,在执行bean的初始化方法前后,修改bean的定义属性,达到影响之后实例化bean的效果 |
| Resource | 提供了统一的获取bean的定义方式。xml方式,url方式等 |
|---|---|
| ResourceLoader | 进一步封装了用于获取Resource的方式。使得用户只需要传入路径,然后判断出是用那种方式获取。 |
未完待续-------------------------------



