zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Java8 lambda表达式语法 1
    Spring WebMVC 4.1返回json时 406(Not Acceptable)
    上传 第三方jar包 nexus
    Nexus 使用配置
    Nexus 安装 使用说明
    mysql 常用命令
    JedisPoolConfig配置
    tomcat 管理端 安全措施
    Java ReentrantLock和synchronized两种锁定机制的对比
    spring 在web容器启动时执行初始化方法
  • 原文地址:https://www.cnblogs.com/edda/p/13497051.html
Copyright © 2011-2022 走看看