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