servlet
- 用
@WebServlet("/hello")
来标注,并且指明要拦截哪些路径
package com.ldc.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello...");
}
}
- 要注册Filter用
@WebFilter
注解、注册Listener用@WebListener
注解;如果在注册的时候,需要一些初始化参数,我们就可以用@WebInitParam
注解
servletContainerInitializer
Shared libraries(共享库) / runtimes pluggability(运行时插件能力)
1、Servlet容器启动会扫描,当前应用里面每一个jar包的ServletContainerInitializer的实现
2、提供ServletContainerInitializer的实现类;
必须绑定在,META-INF/services/javax.servlet.ServletContainerInitializer
文件的内容就是ServletContainerInitializer实现类的全类名;
总结:容器在启动应用的时候,会扫描当前应用每一个jar包里面
META-INF/services/javax.servlet.ServletContainerInitializer
指定的实现类,启动并运行这个实现类的方法;传入感兴趣的类型;
ServletContainerInitializer;
@HandlesTypes;
//容器启动的时候会将@HandlesTypes指定的这个类型下面的子类(实现类或者子接口等)传递过来
//传入感兴趣的类型
@HandlesTypes(value = {HelloService.class})
public class MyServletContainerInitializer implements ServletContainerInitializer {
/**
* 在应用启动的时候,会运行onStartup方法;
* Set<Class<?>> :感兴趣的类型的所有子类型;
* ServletContext 代表当前的web应用的ServletContext对象,一个web应用相当于是一个ServletContext
* @throws ServletException
*/
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
System.out.println("感兴趣的类型:");
set.forEach(System.out::println);
}
}
servletContext
servlet
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("tomcat...");
System.out.println("UserServlet...doGet...");
}
}
filter
public class UserFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//过滤请求
System.out.println("UserFilter...doFilter...");
//放行
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
listener
/**
* 监听项目的启动和停止
*/
public class UserListener implements ServletContextListener {
//监听ServletContextEvent的启动初始化
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("UserListener...contextInitialized");
}
//监听ServletContextEvent销毁
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("UserListener...contextDestroyed");
}
}
注册
//容器启动的时候会将@HandlesTypes指定的这个类型下面的子类(实现类或者子接口等)传递过来
//传入感兴趣的类型
@HandlesTypes(value = {HelloService.class})
public class MyServletContainerInitializer implements ServletContainerInitializer {
/**
* 在应用启动的时候,会运行onStartup方法;
* Set<Class<?>> :感兴趣的类型的所有子类型;
* ServletContext 代表当前的web应用的ServletContext对象,一个web应用相当于是一个ServletContext
* 1)、使用ServletContext注册Web组件(Servlet、Filter、Listener)
* 2)、使用编码的方式,在项目启动的时候给ServletContext添加组件
* 必须在项目启动的时候来添加
* (1)ServletContainerInitializer得到ServletContext对象来注册;
* (2)ServletContextListener的方法的参数里面的ServletContextEvent对象可以获取ServletContext对象
*/
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
System.out.println("感兴趣的类型:");
set.forEach(System.out::println);
//注册组件
Dynamic servlet = servletContext.addServlet("userServlet", new UserServlet());
//配置servlet的映射信息
servlet.addMapping("/user");
//注册Listener
servletContext.addListener(UserListener.class);
//注册Filter
FilterRegistration.Dynamic filter = servletContext.addFilter("userFilter", UserFilter.class);
filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST),true,"/*");
}
}
感兴趣的类型:
class com.ldc.service.AbstractHelloService
class com.ldc.service.HelloServiceImpl
class com.ldc.service.HelloServiceExt
UserListener…contextInitialized
UserFilter…doFilter…
UserFilter…doFilter…
UserFilter…doFilter…
UserServlet…doGet…
整合springMVC
1、web容器在启动的时候,会扫描每个jar包下的META-INF/services/javax.servlet.ServletContainerInitializer
2、加载这个文件指定的类SpringServletContainerInitializer
3、spring的应用一启动会加载感兴趣的WebApplicationInitializer接口的下的所有组件;
4、并且为WebApplicationInitializer组件创建对象(组件不是接口,不是抽象类)
1)、AbstractContextLoaderInitializer:创建根容器;createRootApplicationContext();
2)、AbstractDispatcherServletInitializer:
创建一个web的ioc容器;createServletApplicationContext();
创建了DispatcherServlet;createDispatcherServlet();
将创建的DispatcherServlet添加到ServletContext中;
getServletMappings();
3)、AbstractAnnotationConfigDispatcherServletInitializer:注解方式配置的DispatcherServlet初始化器
创建根容器:createRootApplicationContext()
getRootConfigClasses();传入一个配置类
创建web的ioc容器: createServletApplicationContext();
获取配置类;getServletConfigClasses();
总结:
以注解方式来启动SpringMVC;继承AbstractAnnotationConfigDispatcherServletInitializer;
实现抽象方法指定DispatcherServlet的配置信息;
父子配置类
//Web容器启动的时候创建对象;调用方法来初始化容器以及前端控制器
public class MyWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
//获取父容器的配置类:(Spring的配置文件) --->作为父容器
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class};
}
//获取web容器的配置类(SpringMVC配置文件) --->作为一个子容器
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{AppConfig.class};
}
//获取DispatcherServlet的映射信息
// /:拦截所有请求(包括静态资源(xx.js,xx.png),但是不包括*.jsp)
// /*:拦截所有请求,连*.jsp页面都拦截;jsp页面是tomcat引擎解析的
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
//Spring的容器不扫描Controller,父容器
@ComponentScan(value = {"com.ldc."},excludeFilters = {
@Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
})
public class RootConfig {
}
//SpringMVC只扫描Controller,子容器
//useDefaultFilters = false 禁用默认的过滤规则
@ComponentScan(value = {"com.ldc"},includeFilters = {
@Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)
public class AppConfig {
}
controller
@Controller
public class HelloController {
@Autowired
private HelloService helloService;
@ResponseBody
@RequestMapping("hello")
public String hello() {
String hello = helloService.sayHello("tomcat");
return hello;
}
}
@Service
public class HelloService {
public String sayHello(String name) {
return "Hello," + name;
}
}
定制springMVC
定制SpringMVC;
1)、@EnableWebMvc:开启SpringMVC定制配置功能;
<mvc:annotation-driven/>;
2)、配置组件(视图解析器、视图映射、静态资源映射、拦截器。。。)
extends WebMvcConfigurerAdapter
//SpringMVC只扫描Controller,子容器
//useDefaultFilters = false 禁用默认的过滤规则
@ComponentScan(value = {"com.ldc"},includeFilters = {
@Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer pathMatchConfigurer) {
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer contentNegotiationConfigurer) {
}
@Override
public void configureAsyncSupport(AsyncSupportConfigurer asyncSupportConfigurer) {
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer defaultServletHandlerConfigurer) {
//将SpringMVC处理不了的请求交给tomcat,专门针对于静态资源的,这个时候,静态资源就是可以访问的
defaultServletHandlerConfigurer.enable();
}
@Override
public void addFormatters(FormatterRegistry formatterRegistry) {
//添加自定义的类型转换器
}
@Override
public void addInterceptors(InterceptorRegistry interceptorRegistry) {
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry resourceHandlerRegistry) {
}
@Override
public void addCorsMappings(CorsRegistry corsRegistry) {
}
@Override
public void addViewControllers(ViewControllerRegistry viewControllerRegistry) {
}
@Override
public void configureViewResolvers(ViewResolverRegistry viewResolverRegistry) {
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> list) {
}
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> list) {
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> list) {
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> list) {
}
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> list) {
}
@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> list) {
}
@Override
public Validator getValidator() {
return null;
}
@Override
public MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
- 但是上面直接实现WebMvcConfigurer接口的方式,有很多的方法用不到,我们可以用这个适配器WebMvcConfigurerAdapter来实现,它实现了WebMvcConfigurer接口
//SpringMVC只扫描Controller,子容器
//useDefaultFilters = false 禁用默认的过滤规则
@ComponentScan(value = {"com.ldc"},includeFilters = {
@Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)
@EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
//定制
//视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//默认所有页面都是从/WEB-INF/xxx.jsp
//registry.jsp();
//我们也可以自己来写规则
registry.jsp("/WEB-INF/views/", ".jsp");
}
}
静态资源
//SpringMVC只扫描Controller,子容器
//useDefaultFilters = false 禁用默认的过滤规则
@ComponentScan(value = {"com.ldc"},includeFilters = {
@Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)
@EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
//定制
//视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//默认所有页面都是从/WEB-INF/xxx.jsp
//registry.jsp();
//我们也可以自己来写规则
registry.jsp("/WEB-INF/views/", ".jsp");
}
//静态资源的访问
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
拦截器
public class MyFirstInterceptor implements HandlerInterceptor {
//在目标方法执行之前执行
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("preHandle...");
return true;
}
//在目标方法执行之后执行
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
//页面响应以后执行
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("afterCompletion...");
}
}
//SpringMVC只扫描Controller,子容器
//useDefaultFilters = false 禁用默认的过滤规则
@ComponentScan(value = {"com.ldc"},includeFilters = {
@Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)
@EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
//定制
//视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//默认所有页面都是从/WEB-INF/xxx.jsp
//registry.jsp();
//我们也可以自己来写规则
registry.jsp("/WEB-INF/views/", ".jsp");
}
//静态资源的访问
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
//配置拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//拦截任意的路径
registry.addInterceptor(new MyFirstInterceptor()).addPathPatterns("/**");
}
}
preHandle…
postHandle…
afterCompletion…
preHandle…
postHandle…
afterCompletion…
异步请求
servlet
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(Thread.currentThread()+" start...");
try {
sayHello();
} catch (InterruptedException e) {
e.printStackTrace();
}
resp.getWriter().write("hello...");
System.out.println(Thread.currentThread()+" end...");
}
private void sayHello() throws InterruptedException {
System.out.println(Thread.currentThread()+ " processing...");
Thread.sleep(3000);
}
}
UserFilter…doFilter…
Thread[http-nio-8081-exec-3,5,main] start…
Thread[http-nio-8081-exec-3,5,main] processing…
Thread[http-nio-8081-exec-3,5,main] end…
---------------------
启动服务之后,控制台打印结果为:我们可以发现从线程开始、处理请求到执行结束从始至终都是Thread[http-nio-8081-exec-3,5,main]这个线程,主线程得不到释放,当下一个请求进来就得不到处理
@WebServlet(value = "/async",asyncSupported = true)
public class HelloAsyncServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.支持异步处理:asyncSupported = true
//2.开启异步模式
System.out.println("主线程开始..."+Thread.currentThread()+"==>"+ Instant.now().toEpochMilli());
AsyncContext startAsync = req.startAsync();
//3.业务逻辑进行异步处理,开始异步处理
startAsync.start(()-> {
try {
System.out.println("副线程开始..."+Thread.currentThread()+"==>"+ Instant.now().toEpochMilli());
sayHello();
startAsync.complete();
//获取异步上下文
//AsyncContext asyncContext = req.getAsyncContext();
//4.获取响应
ServletResponse response = startAsync.getResponse();
response.getWriter().write("hello async...");
System.out.println("副线程结束..."+Thread.currentThread()+"==>"+ Instant.now().toEpochMilli());
} catch (Exception e) {
e.printStackTrace();
}
});
System.out.println("主线程结束..."+Thread.currentThread()+"==>"+ Instant.now().toEpochMilli());
}
private void sayHello() throws InterruptedException {
System.out.println(Thread.currentThread()+ " processing..."+"==>"+ Instant.now().toEpochMilli());
Thread.sleep(3000);
}
}
感兴趣的类型:
class com.ldc.service.HelloServiceImpl
class com.ldc.service.HelloServiceExt
class com.ldc.service.AbstractHelloService
UserListener…contextInitialized
[2019-01-18 04:47:06,991] Artifact servlet3.0:war exploded: Artifact is deployed successfully
[2019-01-18 04:47:06,992] Artifact servlet3.0:war exploded: Deploy took 447 milliseconds
UserFilter…doFilter…
UserFilter…doFilter…
UserFilter…doFilter…
主线程开始…Thread[http-nio-8081-exec-7,5,main]>1547801232248
主线程结束…Thread[http-nio-8081-exec-7,5,main]>1547801232253
副线程开始…Thread[http-nio-8081-exec-8,5,main]>1547801232253
Thread[http-nio-8081-exec-8,5,main] processing…>1547801232253
副线程结束…Thread[http-nio-8081-exec-8,5,main]==>1547801235253
springmvc
@Controller
public class AsyncController {
/**
* 1、控制器返回Callable
* 2、Spring异步处理,将Callable 提交到 TaskExecutor 使用一个隔离的线程进行执行
* 3、DispatcherServlet和所有的Filter退出web容器的线程,但是response 保持打开状态;
* 4、Callable返回结果,SpringMVC将请求重新派发给容器,恢复之前的处理;
* 5、根据Callable返回的结果。SpringMVC继续进行视图渲染流程等(从收请求-视图渲染)。
*
* preHandle.../springmvc-annotation/async01
主线程开始...Thread[http-bio-8081-exec-3,5,main]==>1513932494700
主线程结束...Thread[http-bio-8081-exec-3,5,main]==>1513932494700
=========DispatcherServlet及所有的Filter退出线程============================
================等待Callable执行==========
副线程开始...Thread[MvcAsync1,5,main]==>1513932494707
副线程开始...Thread[MvcAsync1,5,main]==>1513932496708
================Callable执行完成==========
================再次收到之前重发过来的请求========
preHandle.../springmvc-annotation/async01
postHandle...(Callable的之前的返回值就是目标方法的返回值)
afterCompletion...
异步的拦截器:
1)、原生API的AsyncListener
2)、SpringMVC:实现AsyncHandlerInterceptor;
* @return
*/
@ResponseBody
@RequestMapping("/async01")
public Callable<String> async01() {
System.out.println("主线程开始..." + Thread.currentThread() + "==>" + Instant.now().getEpochSecond());
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("副线程开始..." + Thread.currentThread() + "==>" + Instant.now().getEpochSecond());
Thread.sleep(2000);
System.out.println("副线程结束..." + Thread.currentThread() + "==>" + Instant.now().getEpochSecond());
return "Callable<String> async01()";
}
};
System.out.println("主线程结束..." + Thread.currentThread() + "==>" + Instant.now().getEpochSecond());
return callable;
}
}
preHandle…
主线程开始…Thread[http-nio-8081-exec-7,5,main]>1547802269
主线程结束…Thread[http-nio-8081-exec-7,5,main]>1547802269
副线程开始…Thread[MvcAsync1,5,main]>1547802269
副线程结束…Thread[MvcAsync1,5,main]>1547802271
preHandle…
postHandle…
afterCompletion…
DeferredResult
public class DeferredResultQueue {
private static Queue<DeferredResult<Object>> queue = new ConcurrentLinkedDeque<>();
public static void save(DeferredResult<Object> deferredResult) {
queue.add(deferredResult);
}
public static DeferredResult<Object> get() {
return queue.poll();
}
}
@Controller
public class AsyncController {
@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;
}
}
- 我们先访问这个创建订单createOrder接口
- 我们再来访问这个create接口
success===>a2769eec-6cc7