Spring 源碼筆記

Spring 源碼筆記

1. Spring MVC初始化流程

​ 1.1 加載配置文件 doLoadConfig(config.getInitParameter(“contextConfigLocation”))

​ 如果是加載Properties相對簡單一點,XML要解析,複雜一點

Properties properties = new Properties();
// 根據web.xml中配置的application.properties路徑名,加載到輸入流
InputStream is = this.getClass().getClassLoader().getResourceAsStream(String location);
properties.load(is);
//此時,配置文件已經加載到properties中

​ 1.2 根據配置文件掃描所有的相關類 doScanner(p.getProperty(“scanPackage”));

List classNames = new ArrayList<>();
//進行遞歸掃描
URL url = this.getClass().getClassLoader().getResource("/"+packageName.replaceAll("\\.","/"));
File classDir = new File(url.getFile());
for(File file : classDir.listFiles()){
	if(file.isDirectory()){
		doScanner(packageName + "." + file.getName());
	}else{
        String className = packageName + "." + file.getName().replace(".class","");
        classNames.add(className);
 }
}

​ 1.3 初始化相關類的實例,並將其放入IOC容器中,也就是MAP中 doInstance()

private Map<String, Object> ioc = new HashMap<String, Object>();
//IOC容器
if(classNames.isEmpty()){
	return;
}
for(String className : classNames){
	Class<?> clazz = class.forName(className);
}

/**
*初始化IOC容器  添加註解的才實例化
*IOC容器規則
*1.key默認用類名首字母小寫
*2.如果用戶自定義,優先選擇用戶自定義名字
*3.如果是接口的話,我們可以巧妙用接口類型作爲key
*/
if(clazz.isAnnotationPresent(Controller.class)){
    //simpleName爲類名,不含路徑信息。方法讓首字母+32得到小寫
    String beanName = lowerFirstCase(clazz.getSimpleName());
}else if(clazz.isAnnotationPresent(Service.class)){
    //2.如果用戶自定義,優先選擇用戶自定義名字
    Service service = clazz.getAnnotation(Service.class);
    String beanName = service.value();
    if("".equals(beanName.trim())){
        beanName =  lowerFirstCase(clazz.getSimpleName());
    }
    Object instance = clazz.newInstance();
    ioc.put(beanName,instance);
    //3.如果是接口的話,我們可以巧妙用接口類型作爲key
    Class<?>[] interfaces = clazz.getInterfaces();
    for(Class<?> i : interfaces){
        ioc.put(i.getName(),instance);
    }
    
    
}else{
    continue;
}

​ 1.4 實現自動依賴注入 doAutowired()

if(ioc.isEmpty()){
	return;
}
for(Map.Entry<String,Object> entry : ioc.entrySet()){
	//獲取所有字段field 無論private protected default都強制注入
	Field[] fields = entry.getValue().getClass().getDeclaredFields();
	for(Field field : fields){
	   if(!field.isAnnotationPresent(Autowried.class)){continue;};
        Autowried autowried = field.getAnnotation(Autowried.class);
        String beanName = autowried.value().trim();
        if("".equals(beanName)){
            beanName = field.getType().getName();
        }
        //想訪問私有的,受保護的 要強制授權訪問
        field.setAccessible(true);
        //疑問:Object instance = entry.getValue(); field爲什麼set兩個對象實例?
        //其實是給對象屬性賦值,第一個參數相當於new出來一個對象,第二個參數是具體值。
        field.set(entry.getValue(),ioc.get(beanName));
		
	}
}

​ 1.5 初始化HandlerMapping initHanlerMapping()

// private Map<String, Method> hanlderMapping = new HashMap<String,Method>();
//改造版:
private List<Handler> handlerMapping = new ArrayList<Handler>();
Handler中含有Method, pattern(正則),paramOrder,controller

if(ioc.isEmpty()){return;}
for(Map.Entry<String,Object> entry : ioc.entrySet()){
    Class<?> clazz = entry.getValue().getClass();
    if(!clazz.isAnnotationPresent(Controller.class)){
        continue;
    }
    String baseUrl = "";
    if(clazz.isAnnotationPresent(Controller.class)){
        RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
        baseUrl = requestMapping.value();
    }
    
    Method[] method = clazz.getMethod();
    for(Method method : methods){
        if(!method.isAnnotationPresent(RequestMapping.class)){
            continue;
        }
        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
        /*
        //多輸入的/替換爲一個
        String url = (baseUrl + requestMapping.value()).replaceAll("/+","/");
        handlerMapping.put(url,method);
        logger.info("Mapping:{},{}",url,method);
        */
        String regex = ("/"+baseUrl+requestMapping.value()).replaceAll("/+","");
        Pattern pattern = Pattern.compile(regex);
        handlerMapping.add(new Handler(pattern,entry.getVallue(),method));
        logger.info("mapping:{},{}",regex,method);

    }
    
}

1.6 doPost()

//運行階段所執行的方法
/*
String url = req.getRequestURI();
String contextPath = req.getContextPath();
url = url.replace(contextPath,"").replaceAll("/+","");
if(!handlerMapping.containsKey(url)){
    resp.getWriter().writer("404 Not Found!");
}
Method m = handlerMapping.get(url);
*/
//改造後:
Handler handler = getHandler(req);
if(handler == null){
    resp.getWriter().writer("404 Not Found!");
    return;
}
//獲取方法參數列表
Class<?> [] paramTypes = handler.method.getParameterTypes();
//保存所有需要自動賦值的參數值
Object[] paramValues = new Object[paramTypes.length];
Map<String,String[]> params = req.getParameterMap();
for(Map.Entry<String,String[]> param : params.entrySet()){
    //第二個參數待確認
    String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]","/");
    //如果找到匹配的對象,則填充參數值
    if(!handler.paramIndexMapping.containsKey(param.getKey())){continue;}
    int index = handler.paramIndexMapping.get(param.getKey());
    paramValues[index] = convert(paramTypes[index], value);
        
}
//設置方法中的request 和 response對象
int reqIndex = handler.paramIndexMapping.get(HttpServletRequest.class.getName());
paramValue[reqIndex] = req;
int respIndex = handler.paramIndexMapping.get(HttpServletResponse.class.getName());
paramValue[respIndex] = req;

private Handler getHandler(HttpServletRequest req){
    if(handlerMapping.isEmpty()){return null;}
    String url = url.replace(contextPath,"").replaceAll("/+","");
    for(Handler handler : handlerMapping){
        Matcher matcher = handler.pattern.matcher(url);
        if(!matcher.matches()){continue;}
        return handler;
    }
    
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章