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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值