- 耦合/依赖
- 在软件系统中,层与层是存在依赖,我们也称之为耦合
- 我们系统架构或者设计的一个原则就是:高内聚低耦合
- 层内部的组成应该是高度聚合的,而层与层之间的关系应该是低耦合的
如何去耦合,是这次的关键
比如在fruiltController中我们还要创建fruiltService对象,在fruiltService中还要创建fruiltDAO对象,几个就耦合在一起了
这里可以将这几个我们需要的几个组件什么Controller,DAO啥的写进xml文件中,然后放入容器beanMap,用id可获得对象,而且在xml里我们还可以设置这个类他需要什么属性,比如刚刚的fruiltController需要用到fruiltService 那我就在fruiltController中加一个属性为fruiltService
<?xml version="1.0" encoding="utf-8" ?>
<beans>
<bean id="fruiltDAO" class="comsr.fruiltDAO"></bean>
<bean id="fruiltService" class="service.fruiltServiceImo">
<!-- property标签用来表示属性:name表示属性名 ref表示引用其他bean的id值-->
<property name="fruiltDAO" ref="fruiltDAO"></property>
</bean>
<!-- 这个bean标签的作用是将来servletpath中涉及的名字对应的是fruilt,那么就要fruiltController这个类来处理-->
<bean id="fruilt" class="comsr.fruiltController">
<property name="fruiltService" ref="fruiltService"></property>
</bean>
<!-- 这个文件里不仅描述了需要哪些bean,也描述了bean与bean之间的关系-->
</beans>
接下来我们就要开始在一个特殊的类中完成这个关系的组合
我们在ClassPathXMLAppication中完成这个工作,我们通过解析XML获得docment,再用document获取Node,因为document是一个树形结构
document.getChilderNode中子节点,判断Node类型是否是NODE.ELEMENT,是就开始获得XML中的id和用反射对应的Class,
还要获得里面标签的属性,用嵌套循环,继续子节点判断Node类型,
然后获得里面的属性分别时propertyname和对应的bean,还是上代码理解吧
public ClassPathXmlApplicationContext(){
try {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("comsr/applicationContext.xml");
//创建DocumentBuilderFactory
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newDefaultInstance();
//创建DocumentBuilder对象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
//创建Document对象
Document document = documentBuilder.parse(inputStream);
//获取所有的bean节点
NodeList bean = document.getElementsByTagName("bean");
for (int i = 0; i < bean.getLength(); i++){
Node beanNode = bean.item(i);
if(beanNode.getNodeType() == Node.ELEMENT_NODE){
//下面的步骤获取了beanid he beanobject 一个是通过docment获取一个是通过反射获取对象,使用beanMap可以将这两者
//进行绑定,实现xml里的id和类绑定
Element beanElement = (Element) beanNode;
String beanid = beanElement.getAttribute("id");
String className = beanElement.getAttribute("class");
Object beanobject = Class.forName(className).newInstance();
beanMap.put(beanid, beanobject);
}
}
//组装bean之间的依赖关系
for (int i = 0; i < bean.getLength(); i++) {
Node beanNode = bean.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);
if(beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){
Element propertyElement = (Element)beanChildNode;
String propertyName = propertyElement.getAttribute("name");
String propertyRef = propertyElement.getAttribute("ref");
//找到property对应的对象
Object refobj = beanMap.get(propertyRef);
//将refobj设置到当前bean对应的实例的property属性上去
Object beanobj = beanMap.get(beanid);
Class aClass = beanobj.getClass();
Field field = aClass.getDeclaredField(propertyName);
field.setAccessible(true);
field.set(beanobj, refobj);
}
}
}
}
总结:IOC,控制反转/ DI - 依赖注入
- 之前在Servlet中,我们创建service对象,fruiltServlet fruiltServlet = new fruiltServletImo();这句话如果出现在servlet中的某个方法内部,那么这个fruiltService的作用域就应该是servlet这个对象级别,但是如果这句话出现在servlet类中,那fruiltservice就是一个成员变量,他的作用域会扩大
- 之后我们在applicationContext.xml中定义了这个fruiltService。然后解析XML,产生fruiltService实例,存放在beanMap中,因此,我们转移了之前的Service实例,dao实例等等它们的生命周期(作用域),控制权从程序员转移到BeanFactory。(控制反转)
依赖注入 - 之前我们在控制层出现代码:fruiltService fruiltService = new fruiltServiceImo(); 那么控制层和service层存在耦合
- 之后我们将代码修改成fruiltService fruiltService = null;
- 在配置文件中设置
<bean id="fruilt" class="comsr.fruiltController">
<property name="fruiltService" ref="fruiltService"></property>
</bean>
自己总结了下控制反转和依赖注入,大概就是Controller方法不负责创建外部对象,只需要有一个外部对象的属性即可,自己不负责创建,这个外部对象属性由容器赋予,也就是注入,然后使用即可,而控制反转就是,中央控制器也不会直接创建对象,而是通过容器获取,然后使用反射调用方法