项目流程图
JavaWeb_z_finally
添加Filter、Listener、TransManager。- 创建IOC容器的权限,从DispatcherServlet中转移到Listener中。
- 使用Filter设置编码(CharacterEncodingFilter)和开启事务管理(OpenSessionInViewFilter)。
补充基础知识
Listener
监听器:专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。
Servlet监听器:Servlet规范中定义的一种特殊类,它用于监听Web应用程序中的ServletContext,HttpSession 和HttpServletRequest等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。
- 监听器的分类:
ServletContextListener - 监听ServletContext对象的创建和销毁的过程
HttpSessionListener - 监听HttpSession对象的创建和销毁的过程
ServletRequestListener - 监听ServletRequest对象的创建和销毁的过程
ServletContextAttributeListener - 监听ServletContext的保存作用域的改动(add,remove,replace)
HttpSessionAttributeListener - 监听HttpSession的保存作用域的改动(add,remove,replace)
ServletRequestAttributeListener - 监听ServletRequest的保存作用域的改动(add,remove,replace)
HttpSessionBindingListener - 监听某个对象在Session域中的创建与移除
HttpSessionActivationListener - 监听某个对象在Session域中的序列化和反序列化
Filter
Filter也属于Servlet规范。
Filter开发步骤:新建类实现Filter接口,然后实现其中的三个方法:init、doFilter、destroy。
Filter在配置时,和servlet一样,也可以配置通配符,例如
@WebFilter("*.do")
表示拦截所有以.do结尾的请求。放行
filterChain.doFilter(servletRequest,servletResponse);
这句话就是放行的意思,意为转给下一个过滤器,若没有过滤器,则直接请求资源。
- 过滤器链
1)执行的顺序依次是: A B C demo03 C2 B2 A2
2)如果采取的是注解的方式进行配置,那么过滤器链的拦截顺序是按照全类名的先后顺序排序的。
3)如果采取的是xml的方式进行配置,那么按照配置的先后顺序进行排序。
事务管理
- 什么是事务?
事务是指是程序中一系列严密的逻辑操作,而且所有操作必须全部成功完成,否则在每个操作中所作的所有更改都会被撤消。可以通俗理解为:就是把多件事情当做一件事情来处理,好比大家同在一条船上,要活一起活,要完一起完 。
事务管理不能在DAO中完成,应该在业务层中完成。
涉及到的组件:
- OpenSessionInViewFilter 实现Filter,重写三个方法。
- TransactionManager beginTrans()开启事务、commit()提交事务、rollback()回滚事务
- ThreadLocal
- ConnUtil getConn()获取连接、closeConn()关闭链接、
- BaseDAO
如图所示:
但是我们使用ThreadLocal
类来解决以上难点。
ThreadLocal称之为本地线程 。 我们可以通过set方法在当前线程上存储数据、通过get方法在当前线程上获取数据。
set方法源码分析:
public void set(T value) { Thread t = Thread.currentThread(); //获取当前的线程 ThreadLocalMap map = getMap(t); //每一个线程都维护各自的一个容器(ThreadLocalMap) if (map != null) map.set(this, value); //这里的key对应的是ThreadLocal,因为我们的组件中需要传输(共享)的对象可能会有多个(不止Connection) else createMap(t, value); //默认情况下map是没有初始化的,那么第一次往其中添加数据时,会去初始化 }
get方法源码分析:
public T get() { Thread t = Thread.currentThread(); //获取当前的线程 ThreadLocalMap map = getMap(t); //获取和这个线程(企业)相关的ThreadLocalMap(也就是工作纽带的集合) if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); //this指的是ThreadLocal对象,通过它才能知道是哪一个工作纽带 if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; //entry.value就可以获取到工具箱了 return result; } } return setInitialValue(); }