Skip to content

Commit

Permalink
xml文件定义bean
Browse files Browse the repository at this point in the history
  • Loading branch information
DerekYRC committed Nov 26, 2020
1 parent e6adc00 commit f173c5c
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 0 deletions.
50 changes: 50 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,57 @@ public class ResourceAndResourceLoaderTest {
}
```

## 在xml文件中定义bean
> 分支:xml-file-define-bean
有了资源加载器,就可以在xml格式配置文件中声明式地定义bean的信息,资源加载器读取xml文件,解析出bean的信息,自动往容器中注册BeanDefinition。

BeanDefinitionReader是读取bean定义信息的抽象接口,XmlBeanDefinitionReader是从xml文件中读取的实现类。BeanDefinitionReader需要有获取资源的能力,且读取bean定义信息后需要往容器中注册BeanDefinition,因此BeanDefinitionReader的抽象实现类AbstractBeanDefinitionReader拥有ResourceLoader和BeanDefinitionRegistry两个属性。

测试:
bean定义文件spring.xml
```
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="person" class="org.springframework.test.ioc.bean.Person">
<property name="name" value="derek"/>
<property name="car" ref="car"/>
</bean>
<bean id="car" class="org.springframework.test.ioc.bean.Car">
<property name="brand" value="porsche"/>
</bean>
</beans>
```

```
public class XmlFileDefineBeanTest {
@Test
public void testXmlFile() throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.loadBeanDefinitions("classpath:spring.xml");
Person person = (Person) beanFactory.getBean("person");
System.out.println(person);
assertThat(person.getName()).isEqualTo("derek");
assertThat(person.getCar().getBrand()).isEqualTo("porsche");
Car car = (Car) beanFactory.getBean("car");
System.out.println(car);
assertThat(car.getBrand()).isEqualTo("porsche");
}
}
```



Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.springframework.beans.factory.support;

import org.springframework.beans.BeansException;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

/**
* @author derekyi
* @date 2020/11/26
*/
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {

private final BeanDefinitionRegistry registry;

private ResourceLoader resourceLoader;

protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
this.registry = registry;
this.resourceLoader = new DefaultResourceLoader();
}

@Override
public BeanDefinitionRegistry getRegistry() {
return registry;
}

@Override
public void loadBeanDefinitions(String[] locations) throws BeansException {
for (String location : locations) {
loadBeanDefinitions(location);
}
}

public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}

@Override
public ResourceLoader getResourceLoader() {
return resourceLoader;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.springframework.beans.factory.support;

import cn.hutool.core.bean.BeanException;
import org.springframework.beans.BeansException;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

/**
* 读取bean定义信息即BeanDefinition的接口
*
* @author derekyi
* @date 2020/11/26
*/
public interface BeanDefinitionReader {

BeanDefinitionRegistry getRegistry();

ResourceLoader getResourceLoader();

void loadBeanDefinitions(Resource resource) throws BeansException;

void loadBeanDefinitions(String location) throws BeansException;

void loadBeanDefinitions(String[] locations) throws BeansException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package org.springframework.beans.factory.xml;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import java.io.InputStream;

/**
* 读取配置在xml文件中的bean定义信息
*
* @author derekyi
* @date 2020/11/26
*/
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

public static final String BEAN_ELEMENT = "bean";
public static final String PROPERTY_ELEMENT = "property";
public static final String ID_ATTRIBUTE = "id";
public static final String NAME_ATTRIBUTE = "name";
public static final String CLASS_ATTRIBUTE = "class";
public static final String VALUE_ATTRIBUTE = "value";
public static final String REF_ATTRIBUTE = "ref";

public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}

@Override
public void loadBeanDefinitions(String location) throws BeansException {
ResourceLoader resourceLoader = getResourceLoader();
Resource resource = resourceLoader.getResource(location);
loadBeanDefinitions(resource);
}

@Override
public void loadBeanDefinitions(Resource resource) throws BeansException {
try {
InputStream inputStream = resource.getInputStream();
try {
doLoadBeanDefinitions(inputStream);
} finally {
inputStream.close();
}
} catch (Exception ex) {
throw new BeansException("IOException parsing XML document from " + resource, ex);
}
}

protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
Document document = XmlUtil.readXML(inputStream);
Element root = document.getDocumentElement();
NodeList childNodes = root.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
if (childNodes.item(i) instanceof Element) {
if (BEAN_ELEMENT.equals(((Element) childNodes.item(i)).getNodeName())) {
//解析bean标签
Element bean = (Element) childNodes.item(i);
String id = bean.getAttribute(ID_ATTRIBUTE);
String name = bean.getAttribute(NAME_ATTRIBUTE);
String className = bean.getAttribute(CLASS_ATTRIBUTE);

Class<?> clazz = Class.forName(className);
//id优先于name
String beanName = StrUtil.isNotEmpty(id) ? id : name;
if (StrUtil.isEmpty(beanName)) {
//如果id和name都为空,将类名的第一个字母转为小写后作为bean的名称
beanName = StrUtil.lowerFirst(clazz.getSimpleName());
}

BeanDefinition beanDefinition = new BeanDefinition(clazz);

for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
if (bean.getChildNodes().item(j) instanceof Element) {
if (PROPERTY_ELEMENT.equals(((Element) bean.getChildNodes().item(j)).getNodeName())) {
//解析property标签
Element property = (Element) bean.getChildNodes().item(j);
String nameAttribute = property.getAttribute(NAME_ATTRIBUTE);
String valueAttribute = property.getAttribute(VALUE_ATTRIBUTE);
String refAttribute = property.getAttribute(REF_ATTRIBUTE);

Object value = valueAttribute;
if (StrUtil.isNotEmpty(refAttribute)) {
value = new BeanReference(refAttribute);
}
PropertyValue propertyValue = new PropertyValue(nameAttribute, value);
beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
}
}
}
getRegistry().registerBeanDefinition(beanName, beanDefinition);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.springframework.test.ioc;

import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.test.ioc.bean.Car;
import org.springframework.test.ioc.bean.Person;

import static org.assertj.core.api.Assertions.assertThat;

/**
* @author derekyi
* @date 2020/11/26
*/
public class XmlFileDefineBeanTest {

@Test
public void testXmlFile() throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.loadBeanDefinitions("classpath:spring.xml");

Person person = (Person) beanFactory.getBean("person");
System.out.println(person);
assertThat(person.getName()).isEqualTo("derek");
assertThat(person.getCar().getBrand()).isEqualTo("porsche");

Car car = (Car) beanFactory.getBean("car");
System.out.println(car);
assertThat(car.getBrand()).isEqualTo("porsche");
}
}
19 changes: 19 additions & 0 deletions src/test/resources/spring.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">

<bean id="person" class="org.springframework.test.ioc.bean.Person">
<property name="name" value="derek"/>
<property name="car" ref="car"/>
</bean>

<bean id="car" class="org.springframework.test.ioc.bean.Car">
<property name="brand" value="porsche"/>
</bean>

</beans>

0 comments on commit f173c5c

Please sign in to comment.