通过tiny-spring学习Spring框架源码(二)
2017-04-16 22:29
465 查看
Spring框架作为使用最多最广泛的Java框架,直接看源码的话,设计层级复杂,容易陷入其中,摸不清框架思路,艺华大神的tiny-spring通过庖丁解牛抽取Spring精华,一步一步拆解非常好的展现框架设计很好的思路,去体会这个经典框架的设计,前面分析过三步之后,接下来从第四步实现通过XML文件加载bean的实现开始继续分析:
public interface BeanDefinitionReader {
void loadBeanDefinition(String location) throws Exception;
}
2.抽象类实现BeanDefinitionReader接口,包含registry和resourceLoader
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {
@Getter
private Map<String, BeanDefinition> registry;
@Getter
private ResourceLoader resourceLoader;
public AbstractBeanDefinitionReader(ResourceLoader resourceLoader) {
this.registry = Maps.newConcurrentMap();
this.resourceLoader = resourceLoader;
}
}3.ResouceLoader类中包含获取Resource的方法public class ResourceLoader {
public Resource getResource(String location) {
URL resource = this.getClass().getClassLoader().getResource(location);
return new UrlResource(resource);
}
}
4.XmlBeanDefinitionReader使用Xml方式实现AbstractBeanDefinitionReader
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {
super(resourceLoader);
}
@Override
public void loadBeanDefinition(String location) throws Exception {
InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
doLoadBeanDefinitions(inputStream);
}
private void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(inputStream);
registerBeanDefinitions(document);
4000
inputStream.close();
}
private void registerBeanDefinitions(Document document) {
Element root = document.getDocumentElement();
parseBeanDefinitions(root);
}
private void parseBeanDefinitions(Element root) {
NodeList childNodes = root.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node item = childNodes.item(i);
if (item instanceof Element) {
Element element = (Element) item;
processBeanDefinition(element);
}
}
}
private void processBeanDefinition(Element element) {
String name = element.getAttribute("name");
String className = element.getAttribute("class");
BeanDefinition beanDefinition = new BeanDefinition();
processProperty(element, beanDefinition);
beanDefinition.setBeanClassName(className);
getRegistry().put(name, beanDefinition);
}
private void processProperty(Element element, BeanDefinition beanDefinition) {
NodeList propertyNode = element.getElementsByTagName("property");
for (int i = 0; i < propertyNode.getLength(); i++) {
Node node = propertyNode.item(i);
if (node instanceof Element) {
Element propertyElement = (Element) node;
String name = propertyElement.getAttribute("name");
String value = propertyElement.getAttribute("value");
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
}
}
}
}
4.其中根据classpath路径获取xml配置bean的输入流,先定义Resource接口
public interface Resource {
InputStream getInputStream() throws IOException;
}5.通过URL方式获取输入流实现类UrlResourceLoader
@AllArgsConstructor
public class UrlResource implements Resource {
private final URL url;
@Override
public InputStream getInputStream() throws IOException {
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
return urlConnection.getInputStream();
}
}
6.定义springioc.xml文件,并对于ResouceLoader写UT进行验证
@Override
protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
Object bean = createBeanInstance(beanDefinition);
applyPropertyValues(bean, beanDefinition);
return bean;
}
private void applyPropertyValues(Object bean, BeanDefinition beanDefinition) throws Exception {
for (PropertyValue propertyValue : beanDefinition.getPropertyValues().getPropertyValueList()) {
Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
declaredField.setAccessible(true);
declaredField.set(bean, propertyValue.getValue());
}
}
private Object createBeanInstance(BeanDefinition beanDefinition) throws InstantiationException, IllegalAccessException {
return beanDefinition.getBeanClass().newInstance();
}
}
public void testXMLBeanRegister() throws Exception {
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
xmlBeanDefinitionReader.loadBeanDefinition("springioc.xml");
BeanFactory beanFactory = new AutowireCapableBeanFactory();
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
HelloSpringIOCService helloSpringIOCService = (HelloSpringIOCService) beanFactory.getBean("helloSpringIOCService");
helloSpringIOCService.helloSpring();
}第四步就完成了从xml中加载bean生成和获取bean,后续会继续讲解IoC的实现。
代码来源:https://github.com/code4craft/tiny-spring
一、实现用xml配置文件方式进行bean读取
1.首先定义读取bean的接口public interface BeanDefinitionReader {
void loadBeanDefinition(String location) throws Exception;
}
2.抽象类实现BeanDefinitionReader接口,包含registry和resourceLoader
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {
@Getter
private Map<String, BeanDefinition> registry;
@Getter
private ResourceLoader resourceLoader;
public AbstractBeanDefinitionReader(ResourceLoader resourceLoader) {
this.registry = Maps.newConcurrentMap();
this.resourceLoader = resourceLoader;
}
}3.ResouceLoader类中包含获取Resource的方法public class ResourceLoader {
public Resource getResource(String location) {
URL resource = this.getClass().getClassLoader().getResource(location);
return new UrlResource(resource);
}
}
4.XmlBeanDefinitionReader使用Xml方式实现AbstractBeanDefinitionReader
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {
super(resourceLoader);
}
@Override
public void loadBeanDefinition(String location) throws Exception {
InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
doLoadBeanDefinitions(inputStream);
}
private void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(inputStream);
registerBeanDefinitions(document);
4000
inputStream.close();
}
private void registerBeanDefinitions(Document document) {
Element root = document.getDocumentElement();
parseBeanDefinitions(root);
}
private void parseBeanDefinitions(Element root) {
NodeList childNodes = root.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node item = childNodes.item(i);
if (item instanceof Element) {
Element element = (Element) item;
processBeanDefinition(element);
}
}
}
private void processBeanDefinition(Element element) {
String name = element.getAttribute("name");
String className = element.getAttribute("class");
BeanDefinition beanDefinition = new BeanDefinition();
processProperty(element, beanDefinition);
beanDefinition.setBeanClassName(className);
getRegistry().put(name, beanDefinition);
}
private void processProperty(Element element, BeanDefinition beanDefinition) {
NodeList propertyNode = element.getElementsByTagName("property");
for (int i = 0; i < propertyNode.getLength(); i++) {
Node node = propertyNode.item(i);
if (node instanceof Element) {
Element propertyElement = (Element) node;
String name = propertyElement.getAttribute("name");
String value = propertyElement.getAttribute("value");
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
}
}
}
}
4.其中根据classpath路径获取xml配置bean的输入流,先定义Resource接口
public interface Resource {
InputStream getInputStream() throws IOException;
}5.通过URL方式获取输入流实现类UrlResourceLoader
@AllArgsConstructor
public class UrlResource implements Resource {
private final URL url;
@Override
public InputStream getInputStream() throws IOException {
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
return urlConnection.getInputStream();
}
}
6.定义springioc.xml文件,并对于ResouceLoader写UT进行验证
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean name="helloSpringIOCService" class="fun.elricboa.spring.ioc.HelloSpringIOCService"> <property name="text" value="Hello World!"></property> </bean> </beans>
public class ResourceLoaderTest { @Test public void test() throws IOException { ResourceLoader resourceLoader = new ResourceLoader(); Resource resource = resourceLoader.getResource("springioc.xml"); InputStream inputStream = resource.getInputStream(); Assert.assertNotNull(inputStream); } }7.测试XmlBeanDefinitionReader
public class XmlBeanDefinitionReaderTest { @Test public void test() throws Exception { XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader()); xmlBeanDefinitionReader.loadBeanDefinition("springioc.xml"); Map<String, BeanDefinition> registry = xmlBeanDefinitionReader.getRegistry(); Assert.assertTrue(registry.size() > 0); } }
二、创建bean实例并注册到beanFactory
public class AutowireCapableBeanFactory extends AbstractBeanFactory {@Override
protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
Object bean = createBeanInstance(beanDefinition);
applyPropertyValues(bean, beanDefinition);
return bean;
}
private void applyPropertyValues(Object bean, BeanDefinition beanDefinition) throws Exception {
for (PropertyValue propertyValue : beanDefinition.getPropertyValues().getPropertyValueList()) {
Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
declaredField.setAccessible(true);
declaredField.set(bean, propertyValue.getValue());
}
}
private Object createBeanInstance(BeanDefinition beanDefinition) throws InstantiationException, IllegalAccessException {
return beanDefinition.getBeanClass().newInstance();
}
}
三、测试
@Testpublic void testXMLBeanRegister() throws Exception {
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
xmlBeanDefinitionReader.loadBeanDefinition("springioc.xml");
BeanFactory beanFactory = new AutowireCapableBeanFactory();
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
HelloSpringIOCService helloSpringIOCService = (HelloSpringIOCService) beanFactory.getBean("helloSpringIOCService");
helloSpringIOCService.helloSpring();
}第四步就完成了从xml中加载bean生成和获取bean,后续会继续讲解IoC的实现。
代码来源:https://github.com/code4craft/tiny-spring
相关文章推荐
- 通过tiny-spring学习Spring框架源码(一)
- 通过tiny-spring学习Spring框架IOC源码(四)
- Spring源码学习之: 通过Spring @PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作
- 【Spring源码学习】Spring框架结构
- spring源码学习笔记-初始化(二)-BeanFactory
- spring源码学习笔记-初始化(三)-BeanFactory
- Spring通过容器获取配置对象及事件注入(学习笔记二)
- Spring源码学习(一)------ IoC
- spring学习笔记之AbstractController源码解读
- 【Spring】IOC核心源码学习(二):容器初始化过程
- spring源码学习笔记-初始化(一)-概览
- spring学习笔记之DispatcherServlet源码解读
- Spring源码学习-容器初始化之FileSystemXmlApplicationContext(二)路径格式及解析方式(上) 推荐
- 开源搜索框架Lucene学习之分词器(4)——通过分词器源码学习装饰者模式
- 通过创建一个位图的XY Chart来学习Android绘图类Rect,Paint,Bitmap,Canvas(附源码)
- spring源码学习笔记-初始化(四)-PostProcessor
- 通过创建一个位图的XY Chart来学习Android绘图类Rect,Paint,Bitmap,Canvas(附源码)
- spring学习笔记:Spring IOC容器,Spring源码
- Spring源码学习(二)------ AOP
- spring源码学习笔记-初始化(六)-完成及异常处理