Spring-Session源码研究之Start_Servlet3.0

这一部分讲解下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};  
    }  

    //......  
}  
  1. 如果决定启用WebInitializer类, 那么spring.xml文件就失效了(不把话说太死, 也暂时不作更深入的研究——例如自定义一个ApplicationContext实现类去既解析注解又解析xml文件)
  2. 而如果不启用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);    
}  
  1. WebApplicationInitializer接口的实现类最终会被SpringServletContainerInitializer所回调. 因为SpringServletContainerInitializer会在对servlet3.0的ServletContainerInitializer接口的实现中回调所有的WebApplicationInitializer实现类(也就是说只要编写了上面的SpringSessionInitializer类和WebInitializer`类).
  2. 其他的工作就交给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,
            "/*");
}
  1. http://blog.csdn.net/patrickyoung6625/article/details/45694157
  2. http://blog.csdn.net/szwandcj/article/details/50225979
package com.org.servlet3; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; /** * @project servlet3.0 * servlet3.0的文件上传 * @date:2012-5-21 *在创建项目的时候首先添加Tomcat7.x的支持,然后把apache-tomcat-7.0.27\conf\web.xml拷贝到项目WEB-INF目录下 *把之前的web.xml覆盖.. 配置留下 <?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> */ @SuppressWarnings("all") @WebServlet(name="fileUploadServlet",urlPatterns="/fileUploadServlet") @MultipartConfig(maxRequestSize=222222)//设置文件上传大小 public class FileUploadServlet extends HttpServlet { /** *访问 *http://localhost:8080/servlet3.0/ */ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); Part part=req.getPart("file"); //获取页面的name //System.out.println(part.getName()); System.out.println(System.getProperty("user.dir"));//输出当前的项目存放的路径 String uploadPath=req.getSession().getServletContext().getRealPath("/upload"); System.out.println(uploadPath);//输出上传的文件路径 String value=part.getHeader("content-disposition");//设置头信息 System.out.println(value); String sub=value.substring(value.lastIndexOf("=")+2,value.length()-1);//截取文件 System.out.println("file size: \t"+part.getSize());//文件的大小 part.write(uploadPath+sub);//写入文件 } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值