SpringMVC加载流程
主要是DispatcherServlet 首先进入到他的静态代码块进行加载资源文件
//加载DispatcherServlet.properties 中相应配置
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
之后会初始化IOC容器 在ApplicationContext中进行初始化IOC
public GPApplicationContext(String location){
InputStream is = null;
try{
//1、定位
is = this.getClass().getClassLoader().getResourceAsStream(location);
//2、载入
config.load(is);
//3、注册,把所有class找出来存着
String packageName = config.getProperty("scanPackage");
doRegister(packageName);
//4、实例化需要ioc的对象(就是加了@Service,@Controller),只要循环class了
doCreateBean();
//5、注入
populate();
}catch(Exception e){
e.printStackTrace();
}
System.out.println("IOC 容器已经初始化");
}
之后进入到initStrategies方法进行对应的初始化
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
之后解析对应的HandMapping
//解析url和Method的关联关系
private void initHandlerMappings(GPApplicationContext context){
Map<String,Object> ioc = context.getAll();
if(ioc.isEmpty()){ return;}
//只要是由Cotroller修饰类,里面方法全部找出来
//而且这个方法上应该要加了RequestMaping注解,如果没加这个注解,这个方法是不能被外界来访问的
for (Entry<String, Object> entry : ioc.entrySet()) {
Class<?> clazz = entry.getValue().getClass();
if(!clazz.isAnnotationPresent(GPController.class)){ continue;}
String url = "";
if(clazz.isAnnotationPresent(GPRequestMapping.class)){
GPRequestMapping requestMapping = clazz.getAnnotation(GPRequestMapping.class);
url = requestMapping.value();
}
//扫描Controller下面的所有的方法
Method [] methods = clazz.getMethods();
for (Method method : methods) {
if(!method.isAnnotationPresent(GPRequestMapping.class)){ continue;}
GPRequestMapping requestMapping = method.getAnnotation(GPRequestMapping.class);
String regex = (url + requestMapping.value()).replaceAll("/+", "/");
Pattern pattern = Pattern.compile(regex);
handlerMapping.add(new Handler(pattern,entry.getValue(),method));
System.out.println("Mapping: " + regex + " " + method.toString());
}
}
//RequestMapping 会配置一个url,那么一个url就对应一个方法,并将这个关系保存到Map中
}
动态匹配参数
//适配器(匹配的过程)
//主要是用来动态匹配我们参数的
private void initHandlerAdapters(GPApplicationContext context){
if(handlerMapping.isEmpty()){ return;}
//参数类型作为key,参数的索引号作为值
Map<String,Integer> paramMapping = new HashMap<String,Integer>();
//只需要取出来具体的某个方法
for (Handler handler : handlerMapping) {
//把这个方法上面所有的参数全部获取到
Class<?> [] paramsTypes = handler.method.getParameterTypes();
//有顺序,但是通过反射,没法拿到我们参数名字
//匹配自定参数列表
for (int i = 0;i < paramsTypes.length ; i ++) {
Class<?> type = paramsTypes[i];
if(type == HttpServletRequest.class ||
type == HttpServletResponse.class){
paramMapping.put(type.getName(), i);
}
}
//这里是匹配Request和Response
Annotation [][] pa = handler.method.getParameterAnnotations();
for (int i = 0; i < pa.length; i ++) {
for(Annotation a : pa[i]){
if(a instanceof GPRequestParam){
String paramName = ((GPRequestParam) a).value();
if(!"".equals(paramName.trim())){
paramMapping.put(paramName, i);
}
}
}
}
adapterMapping.put(handler, new HandlerAdapter(paramMapping));
}
}