上篇博文容器初始化時,使用new的方式來實力化對象,這篇博文咱們利用配置文件+反射實力化對象,進一步封html
裝下降容器和組件的耦合度。下面咱們先看一下配置文件。java
[html] view plain copydom
- <?xml version="1.0" encoding="UTF-8"?>
- <beans>
-
- <bean id="dao" class="com.tgb.container.dao.impl.Dao4MySqlImpl" />
-
- <bean id="service" class="com.tgb.container.service.impl.ServiceImpl" />
-
- </beans>
看到上面的配置文件,除了命名空間沒有,和Spring的配置文件已經很像了,下面咱們就使用dom4j或jdom來讀取ide
配置文件,並將配置文件中配置類利用反射實例化。本實例咱們使用的jdom,你們也可使用dom4j試一下。下面我ui
們看一下讀取配置文件的代碼:this
[java] view plain copyspa
- public interface BeanFactory {
-
- Object getBean(String id);
- }
[java] view plain copy.net
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
-
- import org.jdom.Document;
- import org.jdom.Element;
- import org.jdom.input.SAXBuilder;
- import org.jdom.xpath.XPath;
-
- import com.tgb.container.dao.Dao;
- import com.tgb.container.service.Service;
-
- /**
- * 從類路徑加載配置文件
- *
- * @author liang
- *
- */
- public class ClassPathXmlApplicationContext implements BeanFactory {
-
- // 用於存放Bean
- private Map<String, Object> beans = new HashMap<String, Object>();
-
- public ClassPathXmlApplicationContext(String fileName) {
-
- this.readXML(fileName);
-
- }
-
- // 解析xml文件,經過反射將配置的beasn放到container中,並實現依賴注入
- private void readXML(String fileName) {
- // 建立SAXBuilder對象
- SAXBuilder saxBuilder = new SAXBuilder();
- // 讀取資源,得到document對象
- Document doc;
- try {
- doc = saxBuilder.build(this.getClass().getClassLoader().getResourceAsStream(fileName));
-
- // 獲取根元素
- Element rootEle = doc.getRootElement();
- // 從根元素得到全部的子元素,創建元素集合
- List listBean = XPath.selectNodes(rootEle, "/beans/bean");
-
- // 遍歷根元素的子元素集合,掃描配置文件中的bean
- for (int i = 0; i < listBean.size(); i++) {
- Element bean = (Element) listBean.get(i);
- // 獲取id屬性值
- String id = bean.getAttributeValue("id");
- // 獲取class屬性值
- String clazz = bean.getAttributeValue("class");
- // 反射,實例化
- Object o = Class.forName(clazz).newInstance();
- beans.put(id, o);
- }
-
- // 依賴管理,這裏還不靈活,可是原理是同樣的
- Service service = (Service) beans.get("service");
- Dao dao = (Dao) beans.get("dao");
- // 依賴注入,Service實現依賴dao的實現
- service.setDao(dao);
-
- } catch (Exception e) {
-
- e.printStackTrace();
- }
- }
-
- /**
- * 查找組件
- *
- * @param id
- * @return
- */
- @Override
- public Object getBean(String id) {
- return beans.get(id);
- }
- }
看到上面的代碼,咱們發現讀取配置文件的方法中包含了反射,代碼的可讀性太差,而且對面向對象的封裝不夠徹xml
底,下面咱們將bean的實例化以及依賴注入進行進一步的封裝。htm
封裝bean的實例化
爲了作進一步的封裝,咱們將配置文件的屬性封裝成一個javabean,爲了存放咱們的屬性值。以下所示:
[java] view plain copy
- 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;
- }
-
- }
如今咱們就能夠把bean的實例化作進一步的封裝了。
[java] view plain copy
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
-
- import org.jdom.Document;
- import org.jdom.Element;
- import org.jdom.input.SAXBuilder;
- import org.jdom.xpath.XPath;
-
- import com.tgb.container.dao.Dao;
- import com.tgb.container.service.Service;
-
- /**
- * 容器
- *
- * @author liang
- *
- */
- public class ClassPathXmlApplicationContext implements BeanFactory {
-
- // 用於存放Bean
- private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();
- // 用於存放Bean的實例
- private Map<String, Object> sigletons =new HashMap<String, Object>();
-
-
- public ClassPathXmlApplicationContext(String fileName) {
-
- this.readXML(fileName);
-
- this.instanceBeans();
-
- this.injectObject();
- }
-
- /**
- * 依賴注入,爲bean對象的屬性注入值
- * 這裏還不靈活,可是原理是同樣的
- */
- private void injectObject() {
- Service service = (Service) this.sigletons.get("service");
- Dao dao = (Dao) this.sigletons.get("dao");
- //依賴注入,Service實現依賴dao的實現
- service.setDao(dao);
- }
-
- /**
- * 完成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配置文件
- */
- private void readXML(String fileName) {
- // 建立SAXBuilder對象
- SAXBuilder saxBuilder = new SAXBuilder();
-
- try {
- // 讀取資源,得到document對象
- Document doc = saxBuilder.build(this.getClass().getClassLoader()
- .getResourceAsStream(fileName));
- // 獲取根元素
- Element rootEle = doc.getRootElement();
- // 從根元素得到全部的子元素,創建元素集合
- List listBean = XPath.selectNodes(rootEle, "/beans/bean");
-
- // 遍歷根元素的子元素集合,掃描配置文件中的bean
- for (int i = 0; i < listBean.size(); i++) {
- Element bean = (Element) listBean.get(i);
- // 獲取id屬性值
- String id = bean.getAttributeValue("id");
- // 獲取class屬性值
- String clazz = bean.getAttributeValue("class");
-
- BeanDefinition beanDefine = new BeanDefinition(id,clazz);
- // 將javabean添加到集合中
- beanDefines.add(beanDefine);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
-
- /**
- * 獲取bean實例
- */
- @Override
- public Object getBean(String beanName) {
- return this.sigletons.get(beanName);
- }
-
- }
咱們知道容器不只負責建立對象,並且能夠管理對象的依賴關係,管理對象的生命週期等等。咱們僅實現了容器
靈活建立對象的部分,依賴注入部分是由咱們手動注入的。 對象的依賴關係還不靈活,可是咱們已經可以看到IoC的
影子了,只是形似,尚未達到神似的目標。