BeanFactory - IOC - DI
依赖/耦合
- 软件系统中,层与层间存在依赖关系,称为耦合
- 设计原则:高内聚低耦合 -- 层内组成代码高度聚集,层间关系低耦合(理想情况-零耦合)
如何实现低耦合? 底层代码的改动不影响上层代码
如何实现修改 FruitService 层,其他层,如 FruitController 层,不用做额外修改?
-
将所有层在 applicationContext.xml 文件中预先声明,准备好一个 bean 容器存放每个层的信息以及层间关系
-
<beans> <bean id="fruitDAO" class="com.atguigu.fruit.dao.impl.FruitDAOImpl"/> <bean id="fruitService" class="com.atguigu.fruit.service.impl.FruitServiceImpl"> <!-- property标签用来表示属性;name表示属性名;ref表示引用其他bean的id值--> <property name="fruitDAO" ref="fruitDAO"/> </bean> <bean id="fruit" class="com.atguigu.fruit.controllers.FruitController"> <property name="fruitService" ref="fruitService"/> </bean> </beans>
-
层内没有使用其他层方法,单标签,id-class,通过 id 访问 class
-
层内有调用其他层方法,双标签,标签内添加 property 标签,name-ref,name 是层内使用其他层时,通过 name 调用,ref 表示 name 引用的是哪个层,层内->name->ref->其他层
-
-
创建 beanFactory 接口类,通过 ClassPathXmlApplicationContext 类实现,其中实现从 applicationContext.xml 中获取所有 bean 的 id-class 键值对,存放在 beanMap 映射数组中
-
private Map<String,Object> beanMap = new HashMap<>(); public ClassPathXmlApplicationContext(){ ... InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml"); //1.创建DocumentBuilderFactory DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); //2.创建DocumentBuilder对象 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ; //3.创建Document对象 Document document = documentBuilder.parse(inputStream); //4.获取所有的bean节点 NodeList beanNodeList = document.getElementsByTagName("bean"); for(int i = 0 ; i<beanNodeList.getLength() ; i++){ Node beanNode = beanNodeList.item(i); if(beanNode.getNodeType() == Node.ELEMENT_NODE){ Element beanElement = (Element)beanNode ; String beanId = beanElement.getAttribute("id"); String className = beanElement.getAttribute("class"); Class beanClass = Class.forName(className); //创建bean实例 Object beanObj = beanClass.newInstance() ; //将bean实例对象保存到map容器中 beanMap.put(beanId , beanObj) ; //到目前为止,此处需要注意的是,bean和bean之间的依赖关系还没有设置 } }
-
保存所有的 bean 节点后,还需要根据层间关系,组装 bean 之间的依赖关系
-
从 bean 标签中读取子标签 property
-
public ClassPathXmlApplicationContext(){ ... for(int i = 0 ; i<beanNodeList.getLength() ; i++){ Node beanNode = beanNodeList.item(i); if(beanNode.getNodeType() == Node.ELEMENT_NODE) { Element beanElement = (Element) beanNode; String beanId = beanElement.getAttribute("id"); NodeList beanChildNodeList = beanElement.getChildNodes(); for (int j = 0; j < beanChildNodeList.getLength() ; j++) { Node beanChildNode = beanChildNodeList.item(j); //如果节点是元素节点且节点名 = property 则读取节点内容 if(beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){ Element propertyElement = (Element) beanChildNode; String propertyName = propertyElement.getAttribute("name"); String propertyRef = propertyElement.getAttribute("ref"); //1) 找到propertyRef对应的实例 Object refObj = beanMap.get(propertyRef); //2) 将refObj设置到当前bean对应的实例的property属性上去 Object beanObj = beanMap.get(beanId); Class beanClazz = beanObj.getClass(); Field propertyField = beanClazz.getDeclaredField(propertyName); propertyField.setAccessible(true); propertyField.set(beanObj,refObj); } } } }
-
propertyField.set(beanObj,refObj) 中,beanObj 是当前层,refObj 是要访问的其他层,通过反射将 beanObj 的 property 属性添加 refObj
-