文章目录
0、目标
动作写简版spring之IOC篇的重构,将原有的ClassPathXmlApplicationContext
类拆分多个类。让职责清晰。
1、核心原理
原有的ClassPathXmlApplicationContext
大包大揽,现在只让它做一个组织管理者,具体的工作交给专业的对象。
1、xml文件被抽象为ClassPathXmlResource
(还给它配了一个接口Resource)。
2、定义一个框子SimpleBeanFactory
( 还给它配了一个接口Beanfactory ),给出配置信息,能够获取bean(懒加载)。
3、读取xml的事情,交给XmlBeanDefinitionReader
,它负责读取Resource
后把Bean
的定义配置传给Beanfactory
。
2、类与类之间关系
这些类之间的关联关系如下:
XmlBeanDefinitionReader
类依赖Beanfactory
类,通过构造函数接收Beanfactory
对象,并在loadBeanDefinitions
方法中调用beanfactory
的registerBeanDefinition
方法。SimpleBeanFactory
类实现了Beanfactory
接口,提供了getBean
和registerBeanDefinition
方法的具体实现。ClassPathXmlResource
类实现了Resource
接口,用于从指定的 XML 文件中读取元素信息。ClassPathXmlApplicationContext
类在构造函数中创建了ClassPathXmlResource
、SimpleBeanFactory
和XmlBeanDefinitionReader
对象,并通过XmlBeanDefinitionReader
加载 XML 中的 bean 定义到SimpleBeanFactory
中。同时,提供了getBean
和registerBeanDefinition
方法。Main
类使用ClassPathXmlApplicationContext
来获取 bean 对象。
总的来说,这些类协同工作,实现了一个简单的基于 XML 配置的 IoC 容器的功能。
2.1 BeanDefinition
封装基础配置信息
public class BeanDefinition {
private String id,className;
public BeanDefinition(String id, String className) {
this.id = id;
this.className = className;
}
……
2.2 BeanException
自定义异常
public class BeanException extends Exception {
public BeanException(String message) {
super(message);
}
}
2.3 ClassPathXmlResource
Resource 接口
public interface Resource extends Iterator<Object> {
}
ClassPathXmlResource 类
public class ClassPathXmlResource implements Resource {
private Document document;
private Element rootElement;
private Iterator<Element> elementIterator;
public ClassPathXmlResource(String filename) {
SAXReader saxReader = new SAXReader();
URL resource = this.getClass().getClassLoader().getResource(filename);
try {
this.document = saxReader.read(resource);
this.rootElement = document.getRootElement();
this.elementIterator = this.rootElement.elementIterator();
} catch (DocumentException e) {
e.printStackTrace();
}
}
@Override
public boolean hasNext() {
return this.elementIterator.hasNext();
}
@Override
public Object next() {
return this.elementIterator.next();
}
}
2.4 SimpleBeanFactory
先定义一个接口,Beanfactory 接口
public interface Beanfactory {
Object getBean(String BeanName) throws BeanException;
void registerBeanDefinition(BeanDefinition beanDefinition);
}
SimpleBeanFactory类,就是生成类的工厂,不干别的,目前是懒加载,给定义就行。
public class SimpleBeanFactory implements Beanfactory{
private List<BeanDefinition> definitions = new ArrayList<>();
private List<String> beanNames = new ArrayList<>();
private Map<String,Object> singletons = new HashMap<>();
public SimpleBeanFactory() {
}
@Override
public Object getBean(String beanName) throws BeanException {
Object o = singletons.get(beanName);
if(o==null){
if(!beanNames.contains(beanName)) {
throw new BeanException("Can not find BeanName equals "+ beanName);
}
BeanDefinition beanDefinition = definitions.get(beanNames.indexOf(beanName));
try {
o = Class.forName(beanDefinition.getClassName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
singletons.put(beanDefinition.getId(),o);
}
return o;
}
@Override
public void registerBeanDefinition(BeanDefinition beanDefinition) {
this.definitions.add(beanDefinition);
this.beanNames.add(beanDefinition.getId());
}
}
2.5 XmlBeanDefinitionReader
组装者,胶水。
将Resource
以及 ClassPathXmlResource
的信息写入到 beanfactory
public class XmlBeanDefinitionReader {
Beanfactory beanfactory;
public XmlBeanDefinitionReader(Beanfactory beanfactory) {
this.beanfactory = beanfactory;
}
public void loadBeanDefinitions(Resource resource){
while (resource.hasNext()){
Element element = (Element)resource.next();
String id = element.attributeValue("id");
String aClass = element.attributeValue("class");
BeanDefinition beanDefinition = new BeanDefinition(id, aClass);
this.beanfactory.registerBeanDefinition(beanDefinition);
}
}
}
2.6 ClassPathXmlApplicationContext
一身轻了!
public class ClassPathXmlApplicationContext {
Beanfactory beanfactory;
public ClassPathXmlApplicationContext(String fileName) {
ClassPathXmlResource resource = new ClassPathXmlResource(fileName);
Beanfactory beanfactory = new SimpleBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanfactory);
reader.loadBeanDefinitions(resource);
this.beanfactory = beanfactory;
}
public Object getBean(String beanName) {
try {
return this.beanfactory.getBean(beanName);
} catch (BeanException e) {
e.printStackTrace();
return null;
}
}
public void registerBeanDefinition(BeanDefinition beanDefinition){
this.beanfactory.registerBeanDefinition(beanDefinition);
}
}
结语
这么一来,代码清晰了吗。感觉类变多好多。但是没有关系,就像很多创业公司会演化很多机构一样,ioc要发展 还是要演化出更多的机构,各负其责。
下一篇 3.动手写简版spring之IOC构造函数篇
本专栏做一个简版的spring ,通过动手实践进一步理解ioc、aop、mvc、jdbcTemplate登。
项目代码分享在 https://github.com/forestnlp/minispring