1. 目标
在手写IOC容器–实现功能以面向过程的方式实现了spring IoC容器的基本思路,下面我们以面向对象的思维方式来对该部分的代码进行拆分,进一步模拟spring的IoC实现。
重复强调下自己实现该部分只是为了帮助阅读Spring源码时的理解学习spring的代码结构,不是完整的写一遍Spring,所以仍然只有一些小编理解上的核心逻辑,各位看官也就当个参考就好。
2. Spring IoC中的一些重要接口与类说明
后面的实现会劲量参考着Spring的继承体系来完成以便于在阅读源码时有相应的联想。
2.1 BeanFactory体系中的相关接口和类
相关类和接口UML类图如下
-
BeanFactory:
顶层接口,定义了最为核心的getBean方法,提供容器中是否含有bean、bean是单例还是原型的判断
-
ListableBeanFactory:
用来获取某一类Bean、BeanName、BeanDefinition
-
AutowiredCapableBeanFactory:
用来处理自动注入的bean工厂
-
HierarchicalBeanFactory:
用来处理继承体系的,比如获取 partentBeanFactory
-
ConfigurableBeanFactory:
提供一些配置性的接口,完成bean工厂的配置
-
ConfigurableListBeanFactory:
提供一些配置性的接口,完成listable bean工厂的配置
-
AbstractBeanFactory:
基础的抽象工厂,为ConfigurableBeanFactory SPI提供能力
-
AbstractAutowireCapableBeanFactory:
提供Bean创建(具有构造函数解析),属性填充,自动装配和初始化。
-
DefaultListableBeanFactory:这是一个完整的bean工厂(前面不是接口就是实现类),含有BeanDefinition元数据。通常用它来注册BeanDefinition
-
XmlBeanFactory:通过xml来读取BeanDefinition的工厂
2.2 BeanDefinitionRegistry和SingletonBeanRegistry的实现类及作用
-
BeanDefinitionRegistry
用来保存(hold) BeanDefinition的接口。它是spring中唯一的用来封装BeanDefinition注册的接口
-
SingletonBeanRegistry
为共享(shared) bean实例定义注册的接口。ps:这里所谓的共享实现方式就是单例了
3. 手写简单的IoC容器
把上一节的话搬过来,不过各个需求点的实现就要改成和Spring对应的类(会有简化):
写之前先来看看需要什么(下面给出的代码很多异常、null的处理都没有给出主要聚焦核心流程)
- 为了读取配置类完成解析封装,先搞个流处理把配置文件读进来。
public interface Resource {
InputStream getResource();
}
public class ClasspathResource implements Resource {
private String resource;
public ClasspathResource(String resource) {
this.resource = resource;
}
@Override
public InputStream getResource() {
return this.getClass().getClassLoader().getResourceAsStream(resource);
}
}
-
为了记录BeanDefinition要弄个东西存起来
之前实现我们用的一个Map,这里把Map封装下改成一2.2小节提及的
BeanDefinitionRegistry
,它是一个接口,我们定义get/set方法(名字换了下模仿spring嘛)
public interface BeanDefinitionRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
BeanDefinition getBeanDefinition(String beanName);
}
-
xml解析与BeanDefinition注册
之前我们分析过xml读取后需要封装成
BeanDefinition
对象,需要一个类来解析xml,一个类完成注册。XmlBeanDefinitionReader
控制注册流程,XmlBeanDefinitionDocumentReader
控制解析流程需要转换输入流为
Document
对象使用工具类来完成这一职责。
public class XmlBeanDefinitionReader {
private BeanDefinitionRegistry beanDefinitionRegistry;
public XmlBeanDefinitionReader(BeanDefinitionRegistry beanDefinitionRegistry){
this.beanDefinitionRegistry = beanDefinitionRegistry;
}
public void registerBeanDefinitions(InputStream inputStream){
Document document = DocumentUtils.createDocument(inputStream);
XmlBeanDefinitionDocumentReader xmlBeanDefinitionDocumentReader =
new XmlBeanDefinitionDocumentReader(beanDefinitionRegistry);
// dom解析与beanDefinition注册
xmlBeanDefinitionDocumentReader.loadBeanDefinitions(document.getRootElement());
}
}
public class XmlBeanDefinitionDocumentReader {
private BeanDefinitionRegistry beanDefinitionRegistry;
public XmlBeanDefinitionDocumentReader(BeanDefinitionRegistry beanDefinitionRegistry) {
this.beanDefinitionRegistry = beanDefinitionRegistry;
}
public void loadBeanDefinitions(Element rootElement) {
List<Element> elements = rootElement.elements();
for (Element element : elements) {
String name = element.getName();
if (name.equals("bean")) {//解析bean标签,偷懒就只做了这一个
parseDefaultElement(element);
} else {//解析自定标签
parseCustomElement(element);//没实现,现在也用不到
}
}
}
private void parseDefaultElement(Element beanElement) {
try {
if (Objects.isNull( beanElement )){
return;
}
String id = beanElement.attributeValue("id");
String name = beanElement.attributeValue("name");
String clazzName = beanElement.attributeValue("class");
if (Objects.isNull( clazzName ) || "".equals(clazzName)) {
return;
}
Class<?> clazzType = Class.forName(clazzName);
// 作用域属性,决定bean的创建缓存
String scope = beanElement.attributeValue("scope");
scope = scope == null || "".equals(scope) ? scope : "singleton";
String beanId = id == null ? name : id;
beanId = beanId == null ? clazzType.getSimpleName() : beanId;
BeanDefinition beanDefinition = new BeanDefinition(clazzName, beanId);
beanDefinition.setScope(scope);
List<Element> propertyElements = beanElement.elements();
for (Element propertyElement : propertyElements) {
//解析<property>标签封装为TypedStringValue、RuntimeBeanReference(上一篇有说明)
parsePropertyElement(beanDefinition, propertyElement);
}
//注册BeanDefinition
beanDefinitionRegistry.registerBeanDefinition(beanId, beanDefinition);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private void parsePropertyElement(BeanDefinition beanDefinition, Element propertyElement) {
String name = propertyElement.attributeValue("name");
String value = propertyElement.attributeValue("value");
String ref = propertyElement.attributeValue("ref");
//PropertyValue封装
PropertyValue pv;
if (Objects.nonNull(value ) && !"".equals(value)) {
TypedStringValue typeStringValue = new TypedStringValue(value);
Class<?> targetType =
getTypeByFieldName(beanDefinition.getClazzName(), name);
typeStringValue.setTargetType(targetType);
pv = new PropertyValue(name, typeStringValue);
beanDefinition.addPropertyValue(pv);
} else if (Objects.nonNull(ref ) && !"".equals(ref)) {
RuntimeBeanReference reference = new RuntimeBeanReference(ref);
beanDefinition.addPropertyValue(new PropertyValue(name, reference));
}
}
private Class<?> getTypeByFieldName(String beanClassName, String name) {
Class<?> type = null;
try {
Class<?> clazz = Class.forName(beanClassName);
Field field = clazz.getDeclaredField(name);
type = field.getType();
} catch (Exception e) {
e.printStackTrace();
}
return type;
}
}
-
为了处理BeanDefinition生产的单例bean
同样改成2.2小节提及的
SingletonBeanRegistry
,接口先定义好
public interface SingletonBeanRegistry {
void registerSingleton(String beanName, Object singletonObject);
Object getSingleton(String beanName);
}
说明下:对SingletonBeanRegistry
的实现DefaultSingletonBeanRegistry
直接让AbstractBeanFactory
继承了,实际Spring中是继承的DefaultSingletonBeanRegistry
的子类FactoryBeanRegistrySupport
。后面也会有很多类似的简化处理或者也可以说是偷懒处理
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
// 做单例的缓存
private Map<String, Object> singletonObjects = new HashMap<>();
@Override
public void registerSingleton(String beanName, Object singletonObject) {
this.singletonObjects.put(beanName,singletonObject);
}
@Override
public Object getSingleton(String beanName) {
return this.singletonObjects.get(beanName);
}
}
-
getBean()流程是由
AbstractBeanFactory
来控制,不过它通过模板方法模式将一些实现下沉了。逻辑和上一篇getBean基本相同,不过singletonObject是通过继承DefaultSingletonBeanRegistry实现了,createBean()/getBeanDefinition()的实现下沉到子类。
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
@Override
public Object getBean(String name) {
Object singletonObject = getSingleton(name);
if (Objects.nonNull(singletonObject)) {
return singletonObject;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
singletonObject = createBean(beanDefinition);
if (beanDefinition.isSingleton()) {
registerSingleton(name, singletonObject);
}
return singletonObject;
}
protected abstract BeanDefinition getBeanDefinition(String name);
protected abstract Object createBean(BeanDefinition beanDefinition);
}
creatBean()由AbstractAutowireCapableBeanFactory
完成
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
@Override
public Object createBean(BeanDefinition beanDefinition){
Class<?> clazzType = beanDefinition.getClazzType();
//1.反射创建对象
Object bean = createInstanceBean(clazzType);
//2. DI
populateBean(bean, beanDefinition);
return bean;
}
/**
* 通过beanDefinition记录的PropertyValue完成DI
*/
private void populateBean(Object bean, BeanDefinition beanDefinition) {
List<PropertyValue> propertyValues = beanDefinition.getPropertyValues();
if (Objects.isNull( propertyValues) || propertyValues.isEmpty()){
return;
}
for (PropertyValue pv : propertyValues){
String name = pv.getName();
Object value = pv.getValue();
Object valueDefined = null;
if (value instanceof TypedStringValue) {
TypedStringValue typedStringValue = (TypedStringValue) value;
String stringValue = typedStringValue.getValue();
Class<?> targetType = typedStringValue.getTargetType();
//这里只解析Integer和String两种
if (targetType == Integer.class) {
valueDefined = Integer.parseInt(stringValue);
} else if (targetType == String.class) {
valueDefined = stringValue;
}
} else if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference beanReference = (RuntimeBeanReference) value;
String ref = beanReference.getRef();
valueDefined = getBean(ref);
}
setProperty(bean, name, valueDefined);
}
}
/**
* 反射设置属性
*/
private void setProperty(Object bean, String name, Object valueToUse) {
try {
Class<?> clazz = bean.getClass();
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
field.set(bean, valueToUse);
} catch (Exception e) {
e.printStackTrace();
}
}
//只对无参构造进行实现,spring实际要复杂的多
private Object createInstanceBean(Class<?> clazzType) {
try {
Constructor<?> constructor = clazzType.getDeclaredConstructor();
return constructor.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
registerBeanDefinition()由DefaultListableBeanFactory
完成,注意这个类在spring中有非常重要的地位,这里的实现有点简单
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry {
private Map<String, BeanDefinition> beanDefinitions = new HashMap<>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
beanDefinitions.put(beanName, beanDefinition);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) {
return beanDefinitions.get(beanName);
}
}
最后试测一把
@Test
public void testGetUserById(){
// 配置信息加载
Resource resource = new ClasspathResource("beans.xml");
InputStream inputStream = resource.getResource();
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader =
new XmlBeanDefinitionReader(beanFactory);
xmlBeanDefinitionReader.registerBeanDefinitions(inputStream);
IUserService userService = (IUserService) beanFactory.getBean("userService");
User userById = userService.getUserById(1);
System.out.println(userById);
}
User{id=1, username='wxy', birthday=2020-01-01, sex='male', address='中国'}