【面試題】在瀏覽器輸入登陸地址後,瀏覽器作了什麼?
六步:①域名解析、②tcp握手、③創建鏈接、④發送報文、⑤服務器應答、⑥解析html
域名解析:將英文的網址名轉換成ip地址
tcp鏈接創建:創建通訊信道,通過三次握手
創建鏈接
發送報文:就是消息頭,消息體那些東西
服務器應答:(能夠擴充nginx,服務器集羣等等)
解析html:
(渲染):html
再來看看SpringMVC工做流程
DispatcherServlet
:在web.xml理配置的servlet,前端控制器
,起到一個路由的功能。
HandlerMapping
:以後找到映射控制器,這樣就能夠找到對應的controller了
HandlerAdatper
:經過處理器適配器,能夠找到controller中的方法
拼裝成視圖再返回前端
迷你版的SpringMVC
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.0</version> </dependency>
大體流程思路
①、自定義註解,模擬:@Controller/@Service/@RequestMapping/@Autowired
②、包掃描,類加載實例化,實現@Controller、@Service功能
③、依賴注入,實現@Autowired功能
④、映射處理,實現@RequestMapping功能java
自定義註解,模擬:@Controller/@Service/@RequestMapping/@Autowirednginx
/** * 自注解的Controller * Created by Turing on 2018/12/26 11:38 */ @Documented //註解包含在javadoc中 @Retention(RetentionPolicy.RUNTIME) //註解保留策略,註解在哪一個階段生效【source源碼保存、class字節碼文件保存、runtime運行時仍獲取註解信息(反射須要用到)】 @Target({ElementType.TYPE}) //註解做用的範圍 public @interface Controller { String value() default ""; //經過反射,取出@Controller("xxx"),裏的xxx } /** * Created by Turing on 2018/12/26 12:37 */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) //註解做用的範圍——類上 public @interface Service { String value() default ""; } /** * Created by Turing on 2018/12/26 12:46 */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE,ElementType.METHOD}) //註解做用的範圍——類上,方法上 public @interface RequestMapping { String value() default ""; } /** * Created by Turing on 2018/12/26 12:51 */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) //註解做用的範圍——成員變量上 public @interface Autowired { String value() default ""; }
/** * Created by Turing on 2018/12/26 13:43 */ @Controller @RequestMapping(value = "/test") public class TestController { @Autowired("testService") TestService testService; @RequestMapping("/index") public String index(){ System.out.println(testService.test()+": index"); return testService.test()+"index"; } } /** * Created by Turing on 2018/12/26 13:44 */ @Service public class TestService { public String test(){ return "service test"; } }
<!--前端控制器--> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>com.mvc.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> <!--隨着容器啓動,進行初始化--> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
import com.mvc.annotation.Autowired; import com.mvc.annotation.Controller; import com.mvc.annotation.RequestMapping; import com.mvc.annotation.Service; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 一、想完成Controller和Service的包掃描 * 二、類加載並實例化 * 三、依賴注入 * 四、url和方法關係映射 * Created by Turing on 2018/12/26 13:48 */ public class DispatcherServlet extends HttpServlet { //掃描到的類名,存入list集合中 private List<String> classNames = new ArrayList<String>(); //Controller和Service的實例化,暫存緩存 private Map<String,Object> beans=new HashMap<String,Object>(); //找到方法的映射緩存,暫存 private Map<String,Object> handlerMapping=new HashMap<String,Object>(); @Override //重寫init方法,才能完成目標四步 public void init() throws ServletException { System.out.println("======容器啓動======"); //一、包掃描【正常應該是xml將解析,如今是模擬】 scanPackage("com.mvc"); for (String str : classNames) {//打印,測試下 System.err.println(str); } //二、類加載並實例化 try { createInstance(); } catch (Exception e) { e.printStackTrace(); } for(Map.Entry<String,Object> entry:beans.entrySet()){//打印,測試下 System.out.println(entry.getKey()+"<=======>"+entry.getValue()); } //三、依賴注入 try { injection(); } catch (IllegalAccessException e) { e.printStackTrace(); } //四、URL和方法的關係映射,handlerMapping做用 handlerMapping(); } //一、 private void scanPackage(String packageName) { //類加載的時候,將包結構.替換成/,\\.是正則表達式中的關鍵字符,表明任意字符 String path = packageName.replaceAll("\\.","/"); //classLoader 進行資源加載, URL url = this.getClass().getClassLoader().getResource("/"+path); //遞歸目錄,查找class文件 File[] files = new File(url.getFile()).listFiles(); for (File file : files) { //判斷是否爲目錄 if(file.isDirectory()){ //遍歷目錄 scanPackage(packageName+"."+file.getName()); }else { //掃描到類,先緩存起來,包+類名 拼成 全限定名 classNames.add(packageName+"."+file.getName()); } } } //二、 private void createInstance() throws ClassNotFoundException, IllegalAccessException, InstantiationException { //判斷,沒有掃描到類 if(classNames.isEmpty()){ System.out.println("沒有掃描到類。。。"); return; } //遍歷,類名緩存,加載並初始化 for(String name:classNames){ //類加載時,將類名去調後綴.class String className=name.replace(".class",""); //完成類加載 Class<?> clazz = Class.forName(className); //只關注controller和service,判斷類上是否有對應註解 if(clazz.isAnnotationPresent(Controller.class)){ //實例化類 Object controller = clazz.newInstance(); RequestMapping rm = clazz.getAnnotation(RequestMapping.class); String value = rm.value(); //運行時,取出括號中的值 //保存了RequestMapping括號裏的東西,到對應Controller的映射 beans.put(value,controller); } //拿到servcie if(clazz.isAnnotationPresent(Service.class)){ Object service = clazz.newInstance(); RequestMapping rm = clazz.getAnnotation(RequestMapping.class); String value = rm.value(); beans.put(value,service); } } } //三、 private void injection() throws IllegalAccessException { //判斷,沒有實例化 if(beans.isEmpty()){ System.out.println("沒有實例化。。。"); return; } //遍歷,找到controller,並找到全部字段 for(Map.Entry<String,Object> entry:beans.entrySet()){ //取出對象 Object obj = entry.getValue(); //取出字段 Field[] fields=obj.getClass().getDeclaredFields(); //遍歷,找到@Autowired for (Field field : fields) { if(field.isAnnotationPresent(Autowired.class)){ Autowired autowired = field.getAnnotation(Autowired.class); //取出註解上的值 String value = autowired.value(); //完成注入 field.setAccessible(true);//打開私有,令其能夠訪問 //經過value拿到@Autowired括號裏的實例 field.set(obj,beans.get(value)); } } } } //四、 private void handlerMapping() { //判斷,沒有實例化 if(beans.isEmpty()){ System.out.println("沒有實例化。。。"); return; } //遍歷,找到RequestMapping,並完成映射 for(Map.Entry<String,Object> entry:beans.entrySet()){ //取出對象 Object obj = entry.getValue(); if(obj.getClass().isAnnotationPresent(RequestMapping.class)){ //先拿類上的值 RequestMapping rm = obj.getClass().getAnnotation(RequestMapping.class); String classValue = rm.value(); //再拿方法上的值 Method[] methods=obj.getClass().getMethods(); //遍歷,找到方法上的@RequestMapping for (Method method : methods) { if(method.isAnnotationPresent(RequestMapping.class)){ RequestMapping mapping = method.getAnnotation(RequestMapping.class); String methodValue = mapping.value(); //進行組合,並緩存起來,這樣拿到去到方法的映射 handlerMapping.put(classValue+methodValue,method); } } } } } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String uri = request.getRequestURI(); String context = request.getContextPath(); String path = uri.replaceAll(context, ""); System.err.println(uri+","+context+","+path); //根據"類/方法"路徑,獲取對應的方法 Method method = (Method) handlerMapping.get(path); //獲取對象 Object instance = beans.get("/" + path.split("/")[1]); //分割拿到後邊的方法 try { //反射調用 method.invoke(instance,null); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { super.doGet(request, response); } }