• 设计模式的应用-工厂方法实现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 {
    		
    	}
    
    	
    }
    
  • 相关阅读:
    LNMP源码安装配置
    CentOS6 Apache配置详解(上)
    CentOS6 Apache配置详解(中)
    BZOJ4152 AMPPZ2014 The Captain(最短路)
    BZOJ4028 HEOI2015公约数数列(分块)
    Codeforces Round #517 Div. 1翻车记
    BZOJ4027 HEOI2015兔子与樱花(贪心)
    BZOJ4000 TJOI2015棋盘(状压dp+矩阵快速幂)
    Codeforces Round #510 Div. 2 Virtual Participate记
    BZOJ5190 Usaco2018 Jan Stamp Painting(动态规划)
  • 原文地址:https://www.cnblogs.com/lkqm/p/6435156.html
Copyright © 2020-2023  润新知