Servlet3.0的學習筆記
阿新 • • 發佈:2019-02-04
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<?>> arg0:感興趣的型別的所有子型別; * ServletContext arg1:代表當前Web應用的ServletContext;一個Web應用一個ServletContext; * * 1)、使用ServletContext註冊Web元件(Servlet、Filter、Listener) * 2)、使用編碼的方式,在專案啟動的時候給ServletContext裡面新增元件; * 必須在專案啟動的時候來新增; * 1)、ServletContainerInitializer得到的ServletContext; * 2)、ServletContextListener得到的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, "/*"); } }
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的配置資訊; =========================== 定製SpringMVC; 1)、@EnableWebMvc:開啟SpringMVC定製配置功能; <mvc:annotation-driven/>; 2)、配置元件(檢視解析器、檢視對映、靜態資源對映、攔截器。。。) extends WebMvcConfigurerAdapter
//web容器啟動的時候建立物件;呼叫方法來初始化容器以前前端控制器
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[]{"/"};
}
}
//SpringMVC只掃描Controller;子容器
//useDefaultFilters=false 禁用預設的過濾規則;
@ComponentScan(value="com.zhou",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("/**");
}
}
//Spring的容器不掃描controller;父容器
@ComponentScan(value="com.zhou",excludeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
})
public class RootConfig {
}
@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()+"==>"+System.currentTimeMillis());
AsyncContext startAsync = req.startAsync();
//3、業務邏輯進行非同步處理;開始非同步處理
startAsync.start(new Runnable() {
@Override
public void run() {
try {
System.out.println("副執行緒開始。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis());
sayHello();
startAsync.complete();
//獲取到非同步上下文
AsyncContext asyncContext = req.getAsyncContext();
//4、獲取響應
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);
}
}
@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;
}
/**
* 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()+"==>"+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;
}
}
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();
}
}