1.主要思想就是使用工厂设计模式,将service层和dao层进行解耦

    控制反转就是(inversion of control)将控制权交个自定的一个工厂来实现,我们要做的就是,通过自定义beanfactory 得到需要的serviceiml 和 daoiml对应的类
说白了,不用serviceiml依赖dao层
 

这里使用ServletContextListener 监听器来让tomcat启动时,加载配置文件,

     这里就按照我自己的理解来说明,最近几天研究的结果,当然有老师指导的结果-----------黑马31期

  

java web 项目实现 耦合-解耦 解决方案----工厂模式入门级别_动态代理

java web 项目实现 耦合-解耦 解决方案----工厂模式入门级别_xml_02



   1,进行监听器的实现

      目的:可以第一时间加载配置文件

  2. 配置文件中注册监听器


<!-- 注册Context监听器 -->
<listener>


<listener-class>com.itheima.ebs.web.Listener.ApplicationContextListener</listener-class>


</listener>


  3,当监听器在tomcat启动时加载配置文件。配置文件名:applicationContext.xml (默认)


 

public class ApplicationContextListener implements ServletContextListener {

@Override
public void contextInitialized(ServletContextEvent sce) {

// 0 获得servletContext对象应用
ServletContext context = sce.getServletContext();
// 0.1加载配置
String config = context.getInitParameter("config");

if (config != null) {
// 1.1 处理路径不同情况(我们都知道,配置文件,
//可以放在src下面,可以放在web-inf下)
String[] arr = config.split(":");
//使用流的方式进行读取
InputStream xmls = null;
try {
//如果放在classpath:applicationContext.xml
if (arr.length == 2) {

// 使用类加载器来加载配置文件
xmls = ApplicationContextListener.class.getClassLoader()
.getResourceAsStream(arr[1]);
// 如果在WEB-INF下面
} else if (arr.length == 1) {
//使用servletContext的方法来加载
xmls = context.getResourceAsStream(config); // 放到WEB-INF下
}
} catch (Exception e) {
throw new RuntimeException("资源文件加载不成功" + config);
}
// 如果不等于Null,加载到了配置文件
if (xmls != null) {
// 2使用dom4j进行解析,为了方便查找,我们选在了map容器进行存储
//定义了xmlUtil工具类,方便代码的维护--返回map集合
Map<String, Bean> data = XmlUtil.parserBeanXml(xmls);
//3 将解析结果放置到工厂中
BeanFactory.setBeanData(data);
}
}
}

4. 我们使用dom4j进行解析:
<beans>

<bean name="CategoryDao" class="com.itheima.ebs.dao.impl.CategoryDaoImpl">

</bean>

<bean name="UserDao" class="com.itheima.ebs.dao.impl.UserDaoiml">

</bean>

</beans>


public class XmlUtil {

public static Map<String, Bean> parserBeanXml(InputStream xml) {

try {
//定义一个容器
Map<String, Bean> data = new HashMap<String, Bean>();

// 1解析文件,并获得Document对象
SAXReader reader = new SAXReader();
// 2.获取docuemnt
Document document = reader.read(xml);
// 3 得到 beans
Element root = document.getRootElement();
// 获得bean 元素集合
List<Element> allBeanElements = root.elements();
// 遍历取值(name:value class:value)
for (Element elements : allBeanElements) {

String beanName = elements.attributeValue("name");
String beanClass = elements.attributeValue("class");
// 为了后期方便对xml、
文件中配置扩展使用面向对象封装的思想将bean对象封装到特殊的 bean中
Bean bean = new Bean(beanName, beanClass);

data.put(beanName, bean);
}
//封装好的bean进行返回
return data;

} catch (Exception e) {
throw new RuntimeException(e);
}

}

5 .bean对象的封装

package com.itheima.ebs.Factory;

public class Bean {


private String beanName;
private String beanClass;

public Bean() { }

public Bean(String beanName, String beanClass) {

this.beanName = beanName;
this.beanClass = beanClass;
}

---《 setter/getter方法 》----

}

+++++++++++++++++++++++++++++++++++++++++++++++++++++
BeanFactory:

beanfactory要提供一个自动生对应的bean对象,保证对象的唯一
这里使用单例模式,加上反射思想,通过。class。fornam("类的全限定名").newInstance()



package com.itheima.ebs.Factory;

import java.util.Map;

/**
*
* 实例工厂-单例模式
*
* @return
*/
public class BeanFactory {

private static BeanFactory factory = new BeanFactory();
//存取bean的 key--value 的一个map对象
private static Map<String, Bean> beanData;
//bean 数据缓存集合
private BeanFactory() {}
public static BeanFactory getInstance() {
return factory;
}
//向外部提供一个getbean的方法
//因为是工厂类,所以不依赖任何外部类,使用object作为返回类型
public Object getBean(String beanName) {
try {
//通过bean的名称--value(map.get(key)-----value)
Bean bean=beanData.get(beanName);

String beanclass=bean.getBeanClass();
//初始化一个对象进行返回
return Class.forName(beanclass).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}

}
public static void setBeanData(Map<String, Bean> beanData) {
//从配置文件中读取bean信息传入工厂,从工厂往外取
//使用提供一个set方法来共外界,将解析过的map容器,set到工厂中

BeanFactory.beanData=beanData;
}

}


这样一个简单的解耦,就可以实现了,我们就可以通过配置文件,来指定sevice层--serviceimpl


serviceimpl层和dao层,--dao层和daoimpl的解耦。互相不进行依赖。