从之前的分析中可以知道IOC容器的创建大致分为3步:Resource定位、BeanDefinition载入解析、向容器注册BeanDefinition。
Tiny-spring手动实现了Spring框架,通过对这个源码的解读可以更好更有效的理解Spring。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("tinyioc.xml");
HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");
helloWorldService.helloWorld();
这是我手动创建ioc容器最常见的方式了,但是这段代码底层是如何实现的呢?下面通过tiny-spirng源码分析一下。
回到最初:
BeanDefinition的Resource定位:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("tinyioc.xml");
Resource的接口实现类ClassPathXmlApplicationContext并不能直接被BeanFatory的简单实现类调用,因为ClassPathXmlApplicationContext读取了xml后是由BeanDefnintionReader来处理的。除非是实现了ResourceLoader接口,也就是ApplicationContext及其子类。
BeanDefinition的载入和BeanDefinition注册往下看:
BeanFactory基本容器接口:
public interface BeanFactory {
Object getBean(String name) throws Exception;
}
ApplicationContext继承BeanFatory:
public interface ApplicationContext extends BeanFactory {
}
AbstractApplicationContext实现了ApplicationContext接口:
public abstract class AbstractApplicationContext implements ApplicationContext {
protected AbstractBeanFactory beanFactory;
public AbstractApplicationContext(AbstractBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void refresh() throws Exception {
loadBeanDefinitions(beanFactory);
registerBeanPostProcessors(beanFactory);
onRefresh();
}
protected abstract void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception;
protected void registerBeanPostProcessors(AbstractBeanFactory beanFactory) throws Exception {
List beanPostProcessors = beanFactory.getBeansForType(BeanPostProcessor.class);
for (Object beanPostProcessor : beanPostProcessors) {
beanFactory.addBeanPostProcessor((BeanPostProcessor) beanPostProcessor);
}
}
protected void onRefresh() throws Exception{
beanFactory.preInstantiateSingletons();
}
@Override
public Object getBean(String name) throws Exception {
return beanFactory.getBean(name);
}
}
ClassPathXmlApplicationContext继承AbstractApplicationContext:
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {
private String configLocation;
public ClassPathXmlApplicationContext(String configLocation) throws Exception {
this(configLocation, new AutowireCapableBeanFactory());
}
public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception {
super(beanFactory);
this.configLocation = configLocation;
refresh();
}
@Override
protected void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception {
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
for (Map.Entry beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
}
}
XmlBeanDefinitionReader处理类(核心):
package us.codecraft.tinyioc.beans.xml;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import us.codecraft.tinyioc.BeanReference;
import us.codecraft.tinyioc.beans.AbstractBeanDefinitionReader;
import us.codecraft.tinyioc.beans.BeanDefinition;
import us.codecraft.tinyioc.beans.PropertyValue;
import us.codecraft.tinyioc.beans.io.ResourceLoader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
/**
* @author [email protected]
*/
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {
super(resourceLoader);
}
@Override
public void loadBeanDefinitions(String location) throws Exception {
InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
doLoadBeanDefinitions(inputStream);
}
protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(inputStream);
// 解析bean
registerBeanDefinitions(doc);
inputStream.close();
}
public void registerBeanDefinitions(Document doc) {
Element root = doc.getDocumentElement();
parseBeanDefinitions(root);
}
protected void parseBeanDefinitions(Element root) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
processBeanDefinition(ele);
}
}
}
protected void processBeanDefinition(Element ele) {
String name = ele.getAttribute("id");
String className = ele.getAttribute("class");
BeanDefinition beanDefinition = new BeanDefinition();
processProperty(ele, beanDefinition);
beanDefinition.setBeanClassName(className);
getRegistry().put(name, beanDefinition);
}
private void processProperty(Element ele, BeanDefinition beanDefinition) {
NodeList propertyNode = ele.getElementsByTagName("property");
for (int i = 0; i < propertyNode.getLength(); i++) {
Node node = propertyNode.item(i);
if (node instanceof Element) {
Element propertyEle = (Element) node;
String name = propertyEle.getAttribute("name");
String value = propertyEle.getAttribute("value");
if (value != null && value.length() > 0) {
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
} else {
String ref = propertyEle.getAttribute("ref");
if (ref == null || ref.length() == 0) {
throw new IllegalArgumentException("Configuration problem: element for property '"
+ name + "' must specify a ref or value");
}
BeanReference beanReference = new BeanReference(ref);
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference));
}
}
}
}
}
当执行:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("tinyioc.xml");
ClassPathXmlApplicationContext的构造方法为:
public ClassPathXmlApplicationContext(String configLocation) throws Exception {
this(configLocation, new AutowireCapableBeanFactory());
}
public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception {
super(beanFactory);
this.configLocation = configLocation;
refresh();
}
其中configLocation为传入xml定位,BeanFatory指定了容器的可自动配置。最后调refresh()方法。
public void refresh() throws Exception {
loadBeanDefinitions(beanFactory);
registerBeanPostProcessors(beanFactory);
onRefresh();
}
在refresh()方法中调用了loadBeanDefinitions(beanFactory)和 registerBeanPostProcessors(beanFactory)方法。先看loadBeanDefinitions(beanFactory)方法的实现:
@Override
protected void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception {
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
for (Map.Entry beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
}
底层中是调用了XmlBeanDefinitionReader来读取xml内的bean.loadBeanDefinitions方法是用io流inputStream 读取资源。
@Override
public void loadBeanDefinitions(String location) throws Exception {
InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
doLoadBeanDefinitions(inputStream);
}
doLoadBeanDefinitions(inputStream)方法将读取的资源转换成Document对象,通过registerBeanDefinitions(Document),解析其中的每个Elements。然后得到BeanDefinition然后注册。
protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(inputStream);
// 解析bean
registerBeanDefinitions(doc);
inputStream.close();
}
public void registerBeanDefinitions(Document doc) {
Element root = doc.getDocumentElement();
parseBeanDefinitions(root);
}
protected void parseBeanDefinitions(Element root) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
processBeanDefinition(ele);
}
}
}
protected void processBeanDefinition(Element ele) {
String name = ele.getAttribute("id");
String className = ele.getAttribute("class");
BeanDefinition beanDefinition = new BeanDefinition();
processProperty(ele, beanDefinition);
beanDefinition.setBeanClassName(className);
getRegistry().put(name, beanDefinition);
}
短短的一行代码,却包含了太多的东西:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("tinyioc.xml");
ClassPathXmlApplicationContext构造方法中指定了url和实现BeanFatory接口的容器–AutowireCapableBeanFactory。调用refresh()方法时加载出来了XmlBeanDefinitionReader和registerBeanPostProcessors方法。
通过XmlBeanDefinitionReader将xml中的bean转换成了BeanDefinition并注册;
通过registerBeanPostProcessors接口帮助我们,当需要在Spring容器完成Bean的实例化、配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中。
读源码总是能看到更多的东西。
学习资料git《tiny-Spring》