以往进行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

spring注解-web的更多相关文章

  1. Spring注解驱动开发之web

    前言:现今SpringBoot.SpringCloud技术非常火热,作为Spring之上的框架,他们大量使用到了Spring的一些底层注解.原理,比如@Conditional.@Import.@Ena ...

  2. spring注解源码分析--how does autowired works?

    1. 背景 注解可以减少代码的开发量,spring提供了丰富的注解功能.我们可能会被问到,spring的注解到底是什么触发的呢?今天以spring最常使用的一个注解autowired来跟踪代码,进行d ...

  3. Spring注解

    AccountController .java Java代码   1.        /** 2.         * 2010-1-23 3.         */ 4.        packag ...

  4. spring注解说明之Spring2.5 注解介绍(3.0通用)

    spring注解说明之Spring2.5 注解介绍(3.0通用) 注册注解处理器 方式一:bean <bean class="org.springframework.beans.fac ...

  5. [转]Spring 注解总结

    原文地址:http://blog.csdn.net/wangshfa/article/details/9712379 一 注解优点?注解解决了什么问题,为什么要使用注解? 二 注解的来龙去脉(历史) ...

  6. spring 注解简单使用

    一.通用注解 1.项目结构: 2.新建Person类,注解@Component未指明id,则后期使用spring获取实例对象时使用默认id="person"方式获取或使用类方式获取 ...

  7. 转-Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariable

    转-http://snowolf.iteye.com/blog/1628861/ Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariab ...

  8. Spring 注解总结

    声明:这是转载的.内容根据网上资料整理.相关链接:http://www.360doc.com/content/10/1118/16/2371584_70449913.shtmlhttp://www.i ...

  9. Spring实战5:基于Spring构建Web应用

    主要内容 将web请求映射到Spring控制器 绑定form参数 验证表单提交的参数 对于很多Java程序员来说,他们的主要工作就是开发Web应用,如果你也在做这样的工作,那么你一定会了解到构建这类系 ...

随机推荐

  1. 目录扫描工具 dirsearch 使用详解

    介绍 dirsearch 是一个python开发的目录扫描工具.和我们平时使用的dirb.御剑之类的工具一样,就是为了扫描网站的敏感文件和目录从而找到突破口. 特点 多线程 可保持连接 支持多种后缀( ...

  2. redis sentinel搭建

    /usr/local/bin /usr/local/etc https://www.centos.bz/2017/08/redis-3-x-sentinel-ha-service/ https://w ...

  3. Redis高可用方案哨兵机制------ 配置文件sentinel.conf详解

    Redis的哨兵机制是官方推荐的一种高可用(HA)方案,我们在使用Redis的主从结构时,如果主节点挂掉,这时是不能自动进行主备切换和通知客户端主节点下线的. Redis-Sentinel机制主要用三 ...

  4. CCCC-exercise

    CCCC-exercise 1.L1 总结L1 1-27里面我觉得有东西可以总结的题目 贴了部分的代码 L1-006(20) 一个正整数 N 的因子中可能存在若干连续的数字.例如 630 可以分解为 ...

  5. Linux基础三:用户和组

    三.用户和组 1.概念 (1).用户概念: 用户是用来运行某一些进程.拥有某一些文件或目录. 在Linux里面,用户分成三大类:root用户.系统用户.普通用户. 用户是用UID来唯一标识身份的,且r ...

  6. Linux——搭建Samba(CIFS)服务器

    一.Samba的基本概念 Samba服务:是提供基于Linux和Windows的共享文件服务,服务端和客户端都可以是Linux或Windows操作系统.可以基于特定的用户访问,功能比NFS更强大. S ...

  7. IDEA Plugin,写一个看股票指数和K线的插件

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 没招了,不写点刺激的,你总是不好好看! 以前,我不懂.写的技术就是技术内容,写的场景 ...

  8. [gym101981F]Frank

    在本题中,每一步是独立的,因此即可以看作从$s$移动到$t$的期望步数(对于每一对$s$和$t$都求出答案) 令$f_{i,j}$表示当$s=i$且$t=j$时的答案,则有$f_{i,j}=\begi ...

  9. [gym102832J]Abstract Painting

    考虑每一个圆即对应于区间$[x_{i}-r_{i},x_{i}+r_{i}]$,可以看作对于每一个区间,要求所有右端点严格比其小的区间不严格包含左端点 用$f_{i}$表示仅考虑右端点不超过$i$的区 ...

  10. kibana解决Kibana server is not ready yet问题

    找到kbn的config中的xml配置 将es的ip改成真正的ip