以往进行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. PTA 7-2 邻接表创建无向图 (20分)

    PTA 7-2 邻接表创建无向图 (20分) 采用邻接表创建无向图G ,依次输出各顶点的度. 输入格式: 输入第一行中给出2个整数i(0<i≤10),j(j≥0),分别为图G的顶点数和边数. 输 ...

  2. Power Platform Center of Excellence (CoE) 部署完成&主要内容说明

    随着目前国内使用Power Platform的企业越来越多,而在跟客户交付项目时,客户经常想了解平台的一些基本情况: Power Platform 有多少环境,分别是谁创建和管理? Power Pla ...

  3. Mybatis:插入数据返回自增主键

    使用Mybatis作为工具连接MySQL,要求在插入数据之后返回自增主键 一开始也很迷惑,Mybatis使用insert之后,成功返回的是1,失败会报错或返回0,主键去哪找来 后来知道Mybatis可 ...

  4. PAT A1103—DFS

     Integer Factorization The K−P factorization of a positive integer N is to write N as the sum of the ...

  5. [hdu7020]Array

    (这是一个线性的做法) 显然对于合法的区间,众数是唯一的,因此不妨枚举众数,将众数标记为1.其余数标记为-1,此时问题即求有多少个区间和大于0 考虑暴力的做法:从左到右枚举右端点,记当前前缀和为$to ...

  6. [bzoj1072]排列

    考虑用状压dp枚举排列,即f[i][j]表示当前状态为i,余数为j的方案数,考虑在末尾新增一个字符来转移即可,注意最后答案要除以排列组合 1 #include<bits/stdc++.h> ...

  7. 一文详解MySQL的锁机制

    一.表级锁.行级锁.页级锁 数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则. MySQL数据库由于其自身架构的特点,存在多种数据存储引擎, ...

  8. npm 配置 registry 以及使用 nrm

    由于众所周知的原因,我们的内网链接互联网时非常不稳定,速度慢而且经常下载失败.为了提高下载安装 npm 包的体验,很多人都会把 npm 的 registry 配置成国内镜像,我们一般用的比较多的就是淘 ...

  9. 一个Java发送邮件的案例

    经常有些要发送邮件的需求,但是去网上拷代码老是拷不到能直接运行的,还经常要去以前的项目里面拷,今天直接发出来算了,免得每次都要去别的项目拷. (只支持发送简单的文本文件,发附件的稍微复杂一丢丢,这里就 ...

  10. scanner对象,顺序及选择结构

    scanner对象 基本语法: Scanner s = new Scanner(System.in) 使用next()和nextLine()读取前,使用hasNext()和hasNextLine()来 ...