1. 程式人生 > >Servlet3.0的學習筆記

Servlet3.0的學習筆記

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();
	}

}