设计模式的应用-工厂方法实现3层模型解耦

在web应用中常见的3层架构:控制层(Controller)、业务逻辑(Service)、数据持久层(DAO),控制层调用业务逻辑层,业务逻辑层调用数据层。

这样:

3层架构)

解耦,变成这样:

解耦后的3层架构

首先新建DAO工厂类dao.factory.DaoFactory, 用于创建DAO对象:

/**
 * dao工厂
 * 
 * 注意:工厂类会在类加载的时候为每种DAO只会创建一个dao对象,所以DAO实现类中
 *       不能通过对象包含数据库连接,应该通过ThreadLoacl<Connection>实现每线程一个连接
 * @author
 *
 */

public class DaoFactory {

	/* 保存所有的Dao对象 */
	private static final HashMap<Class<?>,Object> DAO_MAP = new HashMap<>();
	
	static {
		try {
			init();
		} catch(Exception e) {
			// 日志记录
		}
	}

	private static void init() {
		DAO_MAP.put(ManagerDao.class, new ManagerDaoImpl());
		DAO_MAP.put(OrderDao.class, new OrderDaoImpl());
		DAO_MAP.put(SchoolDao.class, new SchoolDaoImpl());
		DAO_MAP.put(UserDao.class, new UserDaoImpl());
	}

	
	@SuppressWarnings("unchecked")
	public static<T> T getDao(Class<T> clazz) {
		// 注:clazz类对应的对象不存在,应该抛出异常
		return (T) DAO_MAP.get(clazz);
	}
}

然后在业务逻辑层实现类中,注入Dao对象,如下:

/**
 * 用户服务类
 */
public class UserServiceImpl implements UserService {

	// 通过工厂方式注入
	private UserDao userDao = DaoFactory.getDao(UserDao.class);

	...
}

遵循开闭原则,新建DAO实现类,只需要工修改厂类即可。

注:可以给DAO实现类添加自定义注解的方式,然后DAO工厂类通过反射,扫描出有指定注解的类,进行注入。

注意多线程问题:

Dao层和Service层均为“实际单例”缓存到map中,Service中持有dao成员变量,Servlet控制层持有service成员变量,由于Dao的使用的数据库连接来自于ThreadLocal变量,所以是线程安全的类,service只持有线程安全的类对象,所以也是线程安全的,同理上推。

然而,在我使用mybatis的过程中,出现了错误!提示“Executor 已经关闭”,mybatis官方资料显示mapper和sqlSession具有同样的声明周期,均是线程不安全的。此时对象之间的关系是Servlet包含service变量,service变量持有mapper对象,mapper对象对应的sqlSession会在一次请求后关闭(一个线程执行后), 此时再次执行会提示类时数据库连接以及关闭的问题!!!

在过滤器中关闭的SqlSession:

/**
 * 系统服务过滤器
 * 过滤字符编码
 * @author
 *
 */
public class OESServiceFilter implements Filter {

	@Override
	public void destroy() {
		
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp,
			FilterChain chain) throws IOException, ServletException {
		req.setCharacterEncoding("utf-8");
		resp.setCharacterEncoding("utf-8");
		
		try{
			chain.doFilter(req, resp);
		}finally{
			// 关闭SqlSession
			MybatisUtil.closeSqlSession();
		}
	}

	@Override
	public void init(FilterConfig config) throws ServletException {
		
	}

	
}
posted @ 2017-02-23 19:50  MarioLuo  阅读(628)  评论(0编辑  收藏  举报