您的位置:首页 > 编程语言 > Java开发

通过tiny-spring学习Spring框架源码(二)

2017-04-16 22:29 465 查看
Spring框架作为使用最多最广泛的Java框架,直接看源码的话,设计层级复杂,容易陷入其中,摸不清框架思路,艺华大神的tiny-spring通过庖丁解牛抽取Spring精华,一步一步拆解非常好的展现框架设计很好的思路,去体会这个经典框架的设计,前面分析过三步之后,接下来从第四步实现通过XML文件加载bean的实现开始继续分析:

一、实现用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();
}
}

三、测试

@Test
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: