Java-web编程的逻辑为:客户端-->servlet-->manager-->dao-->数据库,然后在把数据一层一层返回去,显示给用户。
其中在servlet中要调用manager的方法,就要先实例化一下它;在manager层调用dao就要实例化dao。这样,每一层做的事就不是很纯粹了,不符合高内聚的理论,系统不够灵活。我们就要用一个可以生产各种产品的工厂把他们都生产出来,每一层都和工厂去要,这样就屏蔽了生产细节,也符合现实世界的情况。
1、建立一个配置文件beans-config.xml (其中id为manager接口路径、dao接口路径,class为实现的具体类的路径)
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<service-class>
<service id="com.cxc.drp.basedata.manager.ItemManager" class="com.cxc.drp.basedata.manager.ItemManagerImpl" />
</service-class>
<dao-class>
<dao id="com.cxc.drp.basedata.dao.ItemDao" class="com.cxc.drp.basedata.dao.ItemDaoForOracle" />
</dao-class>
</beans>
2、建立工厂,因为就两个产品就不抽象了,因为抽象还要多建类。这个产品是固定的,就两个,不会在加产品了,要灵活运用抽象工厂。(模式只是一个交流的术语,工厂就是生产一类产品,比如电视工厂:可以生产海尔、长虹等等,但是只能生产一类产品。抽象工厂可以生产一系列产品,电视、冰箱、车、电脑都行,这样多个产品流的工厂就叫抽象工厂)
/**
* 抽象工厂,主要创建两个系列产品
* manager系列
* dao系列
* @author 曹学成
*
*/
public class BeanFactory {
/*
运用单例,只能有一个BeanFactory
单例三要素:
1、静态实例化instance
2、构造函数
3、静态的getInstance方法,并返回instance
*/
//1、静态实例化instance
private static BeanFactory instance =new BeanFactory();
//配置文件的名称
private final String beansConfigFile="beans-config.xml";
//保存service相关对象
private Map serviceMap=new HashMap();
//保存dao相关对象
private Map daoMap=new HashMap();
private Document doc;
//2、构造函数
private BeanFactory(){
try{
//读配置文件内容
doc=new SAXReader().read(Thread.currentThread().getContextClassLoader().getResourceAsStream(beansConfigFile));
}catch (DocumentException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
//3、静态的getInstance方法,并返回instance
public static BeanFactory getInstance(){
return instance;
}
/**
* 根据产品取得service系列产品
* 如果service已经实例化就不再实例化,直接用;否则就实例化
*synchronized 同步的关键字,确保线程安全
* @param beanId
* @return
*/
public synchronized Object getServiceObject(Class s){
if(serviceMap.containsKey(s.getName())){
return serviceMap.get(s.getName());
}
Element beanElement=(Element) doc.selectSingleNode("//service[@id=\""+s.getName() +"\"]");
String className= beanElement.attributeValue("class");
Object service=null;
try {
service= Class.forName(className).newInstance();
//将创建的对象放入map中
serviceMap.put(s.getName(), service);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
return service;
}
/**
* 根据产品取得dao系列产品
* 如果dao已经实例化就不再实例化,直接用;否则就实例化
*synchronized 同步的关键字,确保线程安全
* @param beanId
* @return
*/
public synchronized Object getDaoObject(Class c){
if(daoMap.containsKey(c.getName())){
return daoMap.get(c.getName());
}
Element beanElement=(Element) doc.selectSingleNode("//dao[@id=\""+c.getName() +"\"]");
String className= beanElement.attributeValue("class");
Object dao=null;
try {
dao= Class.forName(className).newInstance();
//将创建的对象放入map中
daoMap.put(c.getName(), dao);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
return dao;
}
3、各层用这个工厂就行了
manager层
private ItemDao itemDao=null;
//在构造函数里面把itemDao付好值,增删改查直接用
public ItemManagerImpl() {
itemDao=(ItemDao)BeanFactory.getInstance().getDaoObject(ItemDao.class);
}
Servlet层
因为servlet有很多,每一层写这个代码很麻烦,所以提取一个AbstractItemServlet。又希望在Tomcat启动时,就把工厂实例化好,因为这个比较费时。
(1)InitServlet
public class InitServlet extends HttpServlet {
@Override
public void init() throws ServletException {
//将抽象工厂放到servletContext中
System.out.println("创建系统的beanFactory");
BeanFactory beanFactory=BeanFactory.getInstance();
this.getServletContext().setAttribute("beanFacotry", beanFactory);
}
}
然后在web.xml中配置一下
讲解:
-
load-on-startup标记容器是否在启动的时候实例化并调用其init()方法的优先级。
-
它的值表示servlet应该被载入的顺序
-
当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个servlet;
-
如果值小于0或未指定时,则表示只有在第一次请求的容器才在该servlet调用初始化函数
-
正值越小,servlet的优先级越高,应用启动时就越先加载。
-
值相同时,容器就会自己选择顺序来加载。
<servlet>
<servlet-name>InitServlet</servlet-name>
<servlet-class>com.cxc.drp.util.InitServlet</servlet-class>
<load-on-startup>2</load-on-startup> <!--2表示在servlet初始化就加载 -->
</servlet>
(2)AbstractItemServlet
public class AbstractItemServlet extends HttpServlet {
protected ItemManager itemManager;
@Override
public void init() throws ServletException {
BeanFactory.getInstance().getServiceObject("itemManager");
//读取放入servletContext中的抽象工厂
BeanFactory beanFactory=(BeanFactory)this.getServletContext().getAttribute("beanFactory");
ItemManager itemManager=(ItemManager) beanFactory.getServiceObject(ItemManager.class);
}
(3)各个具体的servlet继承抽象的servlet,然后用manager就行了