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

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

这样:sql

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对象,以下:mybatis

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

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

    ...
}

遵循开闭原则,新建DAO实现类,只须要工修改厂类便可。多线程

注:能够给DAO实现类添加自定义注解的方式,而后DAO工厂类经过反射,扫描出有指定注解的类,进行注入。架构

注意多线程问题:app

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

然而,在我使用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 {
        
    }

    
}
相关文章
相关标签/搜索