Spring-Session源码研究之Start_Servlet3.0
来源:互联网 发布:温州淘宝运营培训班 编辑:程序博客网 时间:2024/06/10 21:07
这一部分讲解下Spring-Session在Servlet3.0标准下的配置.
姊妹篇《Spring-Session源码研究之Start》
在经过Servlet3.0研究之ServletContainerInitializer接口的讲解之后, 我们可以猜测spring-session是可以通过实现WebApplicationInitializer
来完成功能.
1. 配置
1.1 RedisHttpSessionConfig
类
// 关于这个注解, 直接看Java Doc// 多说一句的是, spring中一般命名为Enablexxxx的注解, 其定义上一般都被会@Import所修饰.@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 7200) public class RedisHttpSessionConfig { // 向Spring容器中注册一个RedisConnectionFactory @Bean public RedisConnectionFactory connectionFactory() { JedisConnectionFactory connectionFactory = new JedisConnectionFactory(); connectionFactory.setPort(6379); connectionFactory.setHostName("10.18.15.190"); return connectionFactory; } }
1.2 WebInitializer
类
// 1. 基类AbstractAnnotationConfigDispatcherServletInitializer最终实现了WebApplicationInitializer接口public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { // 这里如果返回一个/多个配置类, 那么你在web.xml中配置的类型为ContextLoaderListener的<listener/>和<context-param>中的spring.xml就失效了 return new Class[]{RedisHttpSessionConfig.class}; } //...... }
- 如果决定启用
WebInitializer
类, 那么spring.xml文件就失效了(不把话说太死, 也暂时不作更深入的研究——例如自定义一个ApplicationContext实现类去既解析注解又解析xml文件) - 而如果不启用
WebInitializer
类, 就无法获得注解@EnableRedisHttpSession
的好处.
1.3 SpringSessionInitializer
类
// AbstractHttpSessionApplicationInitializer(实现了WebApplicationInitializer接口)是由Spring-Session提供的一个抽象类, 所以我们需要继承自它,并将子类注入到容器中. 以便被servlet3.0的机制之下被加载public class SpringSessionInitializer extends AbstractHttpSessionApplicationInitializer { // 不需要重载或实现任何方法, // 就是为了让支持Servlet3.0的容器能执行基类AbstractHttpSessionApplicationInitializer的代码, 因为就功能而言,Spring-session自身的实现足够了 // 这样也合理, AbstractHttpSessionApplicationInitializer如果是个实体类, 那引入spring-session.jar就默认启用session共享. // 根据配置信息来自定义决定是否载入这个Filter,也就是自主决定是否启用spring-session. String isSingleUserLogin = (String) PropertiesUtil.getProperty("login.singleUserLogin"); if (!("true".equalsIgnoreCase(isSingleUserLogin))) { return; } super.onStartup(servletContext); }
WebApplicationInitializer
接口的实现类最终会被SpringServletContainerInitializer
所回调. 因为SpringServletContainerInitializer
会在对servlet3.0的ServletContainerInitializer
接口的实现中回调所有的WebApplicationInitializer
实现类(也就是说只要编写了上面的SpringSessionInitializer类和
WebInitializer`类).- 其他的工作就交给Spring和Servlet容器了.
2. AbstractHttpSessionApplicationInitializer
类
然后我们观察该类对onStartup(ServletContext servletContext)
方法的实现, 这里我还是给出源码的细节, 大家可以感受下Spring源码的魅力.(相信看过《Clean Code》的读者对这段代码一定非常熟悉)
public void onStartup(ServletContext servletContext) throws ServletException { // 核心逻辑之前的操作 // 没有任何实现细节, 交给子类实现自定义逻辑 beforeSessionRepositoryFilter(servletContext); // 注意这里的configurationClasses要是不为空, 那你在web.xml里配置的spring.xml和ContextLoaderListener就失效了 // 这里就是对应上面的WebInitializer类中的getRootConfigClasses()方法的返回值 if (this.configurationClasses != null) { // 看看这个类名就明白为啥提供配置类, 配置文件就失效了 AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext(); rootAppContext.register(this.configurationClasses); servletContext.addListener(new ContextLoaderListener(rootAppContext)); } // 下面这段逻辑则是web.xml中的配置Filter的模拟 insertSessionRepositoryFilter(servletContext); // 核心逻辑之后的操作 // 依然没有任何实现细节, 交给子类实现自定义逻辑 afterSessionRepositoryFilter(servletContext);}private void insertSessionRepositoryFilter(ServletContext servletContext) { // 这个springSessionRepositoryFilter 是不是很熟悉, 由SpringHttpSessionConfiguration类强制指定, 而这里则是呼应 // DEFAULT_FILTER_NAME = "springSessionRepositoryFilter" String filterName = DEFAULT_FILTER_NAME; DelegatingFilterProxy springSessionRepositoryFilter = new DelegatingFilterProxy( filterName); String contextAttribute = getWebApplicationContextAttribute(); if (contextAttribute != null) { springSessionRepositoryFilter.setContextAttribute(contextAttribute); } registerFilter(servletContext, true, filterName, springSessionRepositoryFilter);}private void registerFilter(ServletContext servletContext, boolean insertBeforeOtherFilters, String filterName, Filter filter) { Dynamic registration = servletContext.addFilter(filterName, filter); if (registration == null) { throw new IllegalStateException( "Duplicate Filter registration for '" + filterName + "'. Check to ensure the Filter is only configured once."); } registration.setAsyncSupported(isAsyncSessionSupported()); EnumSet<DispatcherType> dispatcherTypes = getSessionDispatcherTypes(); // 相信看到这个, 大家就应该非常熟悉了, 尤其是那个"/*" registration.addMappingForUrlPatterns(dispatcherTypes, !insertBeforeOtherFilters, "/*");}
3. Links
- http://blog.csdn.net/patrickyoung6625/article/details/45694157
- http://blog.csdn.net/szwandcj/article/details/50225979
阅读全文
0 0
- Spring-Session源码研究之Start_Servlet3.0
- Spring-Session源码研究之Start
- Spring-Session源码研究之processRequest
- spring源码研究(0)
- Spring源码研究之@Configuration
- spring源码研究之路_IOC
- spring-session源码解析
- Spring源码研究之注解扫描<context:component-scan/>
- Mybatis与Spring集成源码研究之MapperScannerConfigurer
- ViewState与Session之研究
- ViewState与Session之研究
- Spring AOP源码研究笔记
- 研究spring源码有所得
- spring-session源码解读-1
- spring-session源码解读-2
- spring-session源码解读-3
- spring-session源码解读-4
- spring-session源码解读-5
- 周末小总结
- CodeForces
- 生成VS2010的BOOST库
- WEB前端开发:轮播图的实现(H5+C3+JavaScript)(JQuery)
- CodeCoder vs TopForces Gym
- Spring-Session源码研究之Start_Servlet3.0
- 基于tesseract-orc的koa2 OCR Web小应用
- spring cloud使用Feign实现远程接口的调用
- python: 切片符号(slice notation)
- HTTP 500
- [2017.11.11特辑]以一个光棍节表白案例浅谈ECMAScript6模块化的使用方法
- 软件工程(C语言实践篇)学习心得总结
- CodeForces
- 手机扫描识别证件软件颠覆传统录入