在web应用中常见的3层架构:控制层(Controller)、业务逻辑(Service)、数据持久层(DAO),控制层调用业务逻辑层,业务逻辑层调用数据层。
这样:
)
解耦,变成这样:
首先新建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 {
}
}