spring注解-web

  以往进行web项目开发都需要在web.xml配置servlet、filter、listener,在Servlet3.0可以通过注解的方式配置它们(注意:必须用tomcat7以上版本)

@WebServlet

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.getWriter().write("hello...");
    }
}

ServletContainerInitializer

  Servlet容器在启动应用的时候会扫描当前应用每一个jar包里面的META-INF/services/javax.servlet.ServletContainerInitializer;我们可以按照规范在项目的类路径下创建一个META-INF/services/并配置名字为javax.servlet.ServletContainerInitializer的文本,内容就是我们实现ServletContainerInitializer接口的全类名,应用启动就会运行这个实现类的方法,通过@HandlesTypes可以传入我们需要的类

编码的方式添加Web组件(Servlet、Filter、Listener)

  使用ServletContext必须在项目启动的时候注册Web组件,有2种实现方式:ServletContainerInitializer、ServletContextListener接口获取到的ServletContext进行添加

Filter

public class UserFilter implements Filter {

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
            throws IOException, ServletException {
        // 过滤请求
        System.out.println("UserFilter...doFilter...");
        //放行
        arg2.doFilter(arg0, arg1);
        
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub
        
    }

}

HttpServlet

public class UserServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // TODO Auto-generated method stub
        resp.getWriter().write("tomcat...");
    }

}

ServletContextListener

  监听项目的启动和停止

public class UserListener implements ServletContextListener {

    
    //监听ServletContext销毁
    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        // TODO Auto-generated method stub
        System.out.println("UserListener...contextDestroyed...");
    }

    //监听ServletContext启动初始化
    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        // 获取到servletContext进行添加组件
        ServletContext servletContext = arg0.getServletContext();
        System.out.println("UserListener...contextInitialized...");
    }

}

ServletContainerInitializer

容器启动的时候,会运行onStartup方法

@HandlesTypes获取指定的类型下面的子类(实现类,子接口等)传递到arg0中

ServletContext代表一个Web应用上下文

@HandlesTypes(value={HelloService.class})
public class MyServletContainerInitializer implements ServletContainerInitializer {

    /**
     * Set<Class<?>> arg0:感兴趣的类型的所有子类型;
     * ServletContext arg1:代表当前Web应用的ServletContext;
     */
    @Override
    public void onStartup(Set<Class<?>> arg0, ServletContext sc) throws ServletException {
        // TODO Auto-generated method stub
        System.out.println("感兴趣的类型:");
        for (Class<?> claz : arg0) {
            System.out.println(claz);
        }
        
        //注册组件  ServletRegistration  
        ServletRegistration.Dynamic servlet = sc.addServlet("userServlet", new UserServlet());
        //配置servlet的映射信息
        servlet.addMapping("/user");
        
        
        //注册Listener
        sc.addListener(UserListener.class);
        
        //注册Filter  FilterRegistration
        FilterRegistration.Dynamic filter = sc.addFilter("userFilter", UserFilter.class);
        //配置Filter的映射信息
        filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
        
    }

}

异步处理

  支持Servlet的异步处理功能须开启asyncSupported=true(开启异步模式)

@WebServlet(value="/async",asyncSupported=true)
public class HelloAsyncServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("主线程开始。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis());
        AsyncContext startAsync = req.startAsync();
        
     //开始异步处理 startAsync.start(
new Runnable() { @Override public void run() { try { System.out.println("副线程开始。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis()); sayHello();
            //异步处理完毕 startAsync.complete();
//获取到异步上下文 AsyncContext asyncContext = req.getAsyncContext(); //获取响应 ServletResponse response = asyncContext.getResponse(); response.getWriter().write("hello async..."); System.out.println("副线程结束。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis()); } catch (Exception e) { } } }); System.out.println("主线程结束。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis()); } public void sayHello() throws Exception{ System.out.println(Thread.currentThread()+" processing..."); Thread.sleep(3000); } }

servlet3.0整合springMVC

  • 在spring-mvc.jar里的/META-INF/services/javax.servlet.ServletContainerInitializer记录了org.springframework.web.SpringServletContainerInitializer,上面章节讲过web容器在启动的时候会扫描每个jar包下的META-INF/services/javax.servlet.ServletContainerInitializer并加载这个文件指定的类
  • 在这个类中标注了@HandlesTypes(WebApplicationInitializer.class),所以在应用启动的时候会加载WebApplicationInitializer接口下的所有组件,并且为WebApplicationInitializer组件创建对象(组件不是接口,不是抽象类);这个组件有三个抽象类:
  • AbstractContextLoaderInitializer:
    • createRootApplicationContext()  //创建根容器
  • AbstractDispatcherServletInitializer:
    • createServletApplicationContext()  //创建web的ioc容器
    • createDispatcherServlet()  //创建DispatcherServlet,将它添加到到ServletContext中
    • getServletMappings()  //servlet映射地址
  • AbstractAnnotationConfigDispatcherServletInitializer  //注解方式配置
    • createRootApplicationContext()      //创建根容器
    • getRootConfigClasses()                  //传入spring的配置类
    • createServletApplicationContext()  //创建web的ioc容器
    • getServletConfigClasses()             //获取配置类

实现

  以注解方式启动SpringMVC,我们只要继承AbstractAnnotationConfigDispatcherServletInitializer实现抽象方法(指定DispatcherServlet的配置信息)

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    //获取根容器的配置类;(Spring的配置文件)   父容器;
    @Override
    protected Class<?>[] getRootConfigClasses() {
        // TODO Auto-generated method stub
        return new Class<?>[]{RootConfig.class};
    }

    //获取web容器的配置类(SpringMVC配置文件)  子容器;
    @Override
    protected Class<?>[] getServletConfigClasses() {
        // TODO Auto-generated method stub
        return new Class<?>[]{AppConfig.class};
    }

    //获取DispatcherServlet的映射信息
    //  /:拦截所有请求(包括静态资源(xx.js,xx.png)),但是不包括*.jsp;
    //  /*:拦截所有请求;连*.jsp页面都拦截;jsp页面是tomcat的jsp引擎解析的;
    @Override
    protected String[] getServletMappings() {
        // TODO Auto-generated method stub
        return new String[]{"/"};
    }

  spring容器

//Spring的容器不扫描controller;父容器
@ComponentScan(value="com.atguigu",excludeFilters={
        @Filter(type=FilterType.ANNOTATION,classes={Controller.class})
})
public class RootConfig {

}

  web容器

@EnableWebMvc等同于xml配置<mvc:annotation-driven/>
配置组件(视图解析器、视图映射、静态资源映射、拦截器。。。) extends WebMvcConfigurerAdapter
//SpringMVC只扫描Controller;子容器
//useDefaultFilters=false 禁用默认的过滤规则;
@ComponentScan(value="com.atguigu",includeFilters={
        @Filter(type=FilterType.ANNOTATION,classes={Controller.class})
},useDefaultFilters=false)
@EnableWebMvc 
public class AppConfig  extends WebMvcConfigurerAdapter  {//视图解析器
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        // TODO Auto-generated method stub
        //默认所有的页面都从 /WEB-INF/ xxx .jsp
        //registry.jsp();
        registry.jsp("/WEB-INF/views/", ".jsp");
    }
    
    //静态资源访问
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        // TODO Auto-generated method stub
        configurer.enable();
    }
    
    //拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // TODO Auto-generated method stub
        //super.addInterceptors(registry);
        registry.addInterceptor(new MyFirstInterceptor()).addPathPatterns("/**");
    }

}
public class MyFirstInterceptor implements HandlerInterceptor {

    //目标方法运行之前执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // TODO Auto-generated method stub
        System.out.println("preHandle..."+request.getRequestURI());
        return true;
    }

    //目标方法执行正确以后执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("postHandle...");

    }

    //页面响应以后执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub
        System.out.println("afterCompletion...");
    }

}

springmvc异步处理

  springmvc异步处理有两种方式:controller方法返回类型是Callable和DeferredResult

Callable

  • 在方法返回类型为Callable的时候,将callable对象提交到TaskExecutor,主线程会开启一个隔离的线程进行异步处理,剩余流程继续执行不会等待
  • 方法执行完DispatcherServlet和所有的Filter退出web容器的线程,但是response保持打开状态
  • 当Callable返回结果,SpringMVC将请求又重新派发给容器进行之前的处理,继续进行视图渲染流程等(从收请求-视图渲染)
@ResponseBody
    @RequestMapping("/async01")
    public Callable<String> async01(){
        System.out.println("主线程开始..."+Thread.currentThread()+"==>"+System.currentTimeMillis());
        
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("副线程开始..."+Thread.currentThread()+"==>"+System.currentTimeMillis());
                Thread.sleep(2000);
                System.out.println("副线程开始..."+Thread.currentThread()+"==>"+System.currentTimeMillis());
                return "Callable<String> async01()";
            }
        };
        
        System.out.println("主线程结束..."+Thread.currentThread()+"==>"+System.currentTimeMillis());
        return callable;
    }

  执行流程:HandlerInterceptor的preHandle()-》目标方法,执行完后DispatcherServlet及所有的Filter退出线程-》执行Callable,完成后再次重发请求,拦截器会又一次打印preHandle(),并且剩余的postHandle、afterCompletion依次执行

DeferredResult

deferredResult保存到队列中,写个监听器监听这个队列是否变化,如果有就触发create()进行业务处理,从队列拿到DeferredResult并把处理的结果保存回去

   @ResponseBody
    @RequestMapping("/createOrder")
    public DeferredResult<Object> createOrder(){
        DeferredResult<Object> deferredResult = new DeferredResult<>((long)3000, "create fail...");       
        DeferredResultQueue.save(deferredResult);
        return deferredResult;
    }
    
    
    @ResponseBody
    @RequestMapping("/create")
    public String create(){
        //创建订单
        String order = UUID.randomUUID().toString();
        DeferredResult<Object> deferredResult = DeferredResultQueue.get();
        deferredResult.setResult(order);
        return "success===>"+order;
    }

  public class DeferredResultQueue { private static Queue<DeferredResult<Object>> queue = new ConcurrentLinkedQueue<DeferredResult<Object>>(); public static void save(DeferredResult<Object> deferredResult){ queue.add(deferredResult); } public static DeferredResult<Object> get( ){ return queue.poll(); } }

异步的拦截器

  • 原生API的AsyncListener
  • 实现AsyncHandlerInterceptor接口

同步:request请求-》目标方法运行之前执行拦截器的preHandle()-》目标方法-》目标方法执行正确以后执行拦截器的postHandle()-》页面响应以后执行afterCompletion

控制器返回Callable

原文地址:https://www.cnblogs.com/edda/p/13497051.html