编码剖析Spring管理Bean的原理
在Spring的第一个案例中,我们已经知道了怎么将bean交给Spring容器进行管理,并且明白了怎么从Spring容器中获取bean。那我们就有一个疑问了:Spring是如何创建并管理bean的呢?现在我们就来编码剖析Spring管理Bean的原理。
本文是在Spring的第一个案例的基础上展开的。
我们要使用dom4j读取Sping的配置文件——beans.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"></bean> </beans>
那么就需要将dom4j所需的jar包导入该项目中。dom4j所需的jar包为:
- dom4j-1.6.1.jar
- jaxen-1.1-beta-6.jar
dom4j读取到诸如
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"></bean>
这样的内容时,务必需要将读取到的bean的信息存到一个JavaBean对象中。于是我们可在junit.test包下创建这样一个JavaBean——BeanDefinition.java,其代码为:
/** * 将读取到的bean的信息存到一个JavaBean对象中 * */ public class BeanDefinition { private String id; private String className; public BeanDefinition(String id, String className) { this.id = id; this.className = className; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } }
接下来我们就创建一个传智播客版的Spring容器来模拟Spring容器。在junit.test下新建一个类——ItcastClassPathXMLApplicationContext.java,其代码如下:
/** * 传智播客版Spring容器 * */ public class ItcastClassPathXMLApplicationContext { private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>(); private Map<String, Object> sigletons = new HashMap<String, Object>(); public ItcastClassPathXMLApplicationContext(String filename) { this.readXML(filename); this.instanceBeans(); } /** * 完成bean的实例化 */ private void instanceBeans() { for (BeanDefinition beanDefinition : beanDefines) { try { if (beanDefinition.getClassName() != null && !"".equals(beanDefinition.getClassName().trim())) { sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance()); } } catch (Exception e) { e.printStackTrace(); } } } /** * 读取XML配置文件 * @param filename */ private void readXML(String filename) { SAXReader saxReader = new SAXReader(); Document document = null; try { URL xmlpath = this.getClass().getClassLoader().getResource(filename); document = saxReader.read(xmlpath); Map<String, String> nsMap = new HashMap<String, String>(); nsMap.put("ns", "http://www.springframework.org/schema/beans"); // 加入命名空间 XPath xsub = document.createXPath("//ns:beans/ns:bean"); // 创建beans/bean查询路径 xsub.setNamespaceURIs(nsMap); // 设置命名空间 List<Element> beans = xsub.selectNodes(document); // 获取文档下所有bean节点 for (Element element : beans) { String id = element.attributeValue("id"); // 获取id属性值 String clazz = element.attributeValue("class"); // 获取class属性值 BeanDefinition beanDefine = new BeanDefinition(id, clazz); beanDefines.add(beanDefine); } } catch (Exception e) { e.printStackTrace(); } } /** * 获取bean实例 * @param beanName * @return */ public Object getBean(String beanName) { return this.sigletons.get(beanName); } }
这样,传智播客版的Spring容器就创建出来了。接下来我们就要测试传智播客版的Spring容器是否能够取得bean实例,只须修改SpringTest类的代码为:
public class SpringTest { @Test public void test() { // ApplicationContext是接口 // ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); // 实例化Spring容器 // PersonService personService = (PersonService) ctx.getBean("personService"); // 从Spring容器取得bean // personService.save(); ItcastClassPathXMLApplicationContext ctx = new ItcastClassPathXMLApplicationContext("beans.xml"); // 实例化Spring容器 PersonService personService = (PersonService) ctx.getBean("personService"); // 从Spring容器取得bean personService.save(); } }
测试test()方法,Eclipse控制台打印如下:
通过编写代码剖析Spring管理Bean的原理,我们就能深刻理解Spring内部到底是如何创建并管理bean实例的.
笔者寄语:人生没有白走的路,每一步,都算数。