仿写SpringMvc底层源码

     一直没有记笔记的习惯,就在此时,决定将自己每一次进步都记录下来。经过几次国内大公司面试。目前而言:对java的理解是停留在运用框架和中间件的层次上,对于底层原理并没有深刻去理解。所以让我决定重新学习java的想法。花了一点时间,将springMvc从底层进行了简单分析。从web.xml,配置加载,常用注解,我们将底层重新进行简单的开发,目的了解spring的底层思想。

首先从几个题目出发:

1.什么是spring框架?spring框架有哪些模块?

2.使用spring框架带来什么好处?

3.什么是控制反转?什么是依赖注入?

4.BeanFactory和Application有什么区别?

5.Spring的生命周期?

6.SpringBean各作用域区别?

7.spring单例bean是否线程安全?

8.AOP底层原理?

9.Spring怎么管理事务?

对于以上问题的理解,我认为我们应该动手将spring源码自己敲敲看!看源码最难是思想,然后就找入口。

首先我们分析spring加载过程:我们分三块来理解:

一,配置阶段:

1.web.xml

2.dispatcherServlet->springweb开发入口

3.application.xml

4.url-patten->映射url

二.初始化:

1.init()->有web容器调用servlet初始化

2.加载配置文件

3.初始化IOC容器

4.依赖注入

5.初始化HandlerMapping

三.运行阶段

1.doservice()->用户请求调用

2.request.getUrl->获取url

3.匹配url对应的方法

4.调用method

5.利用response返回web


下面我们通过 上面的步骤,我们将springMvc重新开发一遍。



工程结构:




web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>my-spring</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>


<servlet>
<servlet-name>iflytekMvc</servlet-name>
<servlet-class>com.iflytek.spring.servlet.IflytekDisPatcherSevlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>application.properties</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
     
    </servlet>
    <servlet-mapping>
    <servlet-name>iflytekMvc</servlet-name>
    <url-pattern>/*</url-pattern>
    
    
    </servlet-mapping>
</web-app>

package com.iflytek.spring.controller;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import com.iflytek.spring.annotation.IflytekAutowrited;

import com.iflytek.spring.annotation.IflytekController;
import com.iflytek.spring.annotation.IflytekRequestMapping;
import com.iflytek.spring.annotation.IflytekRequestParam;
import com.iflytek.spring.service.ISpringService;

/**

 * 一个非常简单的Controller

 * @author: [email protected]
 * @created:Apr 6, 2018 8:09:23 PM
 * @version: 1.0
 * @lastModified
 */
@IflytekController
public class SpringController {
@IflytekAutowrited
private ISpringService springService;
@IflytekRequestMapping("/query.do")
public String query(HttpServletRequest req, HttpServletResponse resp,@IflytekRequestParam("id") String id){
return springService.query(id);
}

}

package com.iflytek.spring.service;
/** 
 * 定义一个接口
 * 
 * @author: [email protected]
 * @created:Apr 6, 2018 8:10:06 PM 
 * @version: 1.0 
 * @lastModified
*/
public interface ISpringService {
public String query(String id);
}

package com.iflytek.spring.service;


import com.iflytek.spring.annotation.IflytekService;


/** 
 * 实现类
 * @author: [email protected]
 * @created:Apr 6, 2018 8:10:28 PM 
 * @version: 1.0 
 * @lastModified
*/
@IflytekService
public class SpringServiceImpl implements  ISpringService{
   public String query(String id) {
return id;

}

}

下面我们将注解重新开发:

package com.iflytek.spring.annotation;


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


package com.iflytek.spring.annotation;


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/** 
 * @Autowrited注解
 * @author: [email protected]
 * @created:Apr 6, 2018 8:06:35 PM 
 * @version: 1.0 
 * @lastModified
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IflytekAutowrited {
String value() default "";
}


package com.iflytek.spring.annotation;


import java.lang.annotation.Target;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;


/** 
 * @Controller注解
 * @author: [email protected]
 * @created:Apr 6, 2018 8:04:52 PM 
 * @version: 1.0 
 * @lastModified
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IflytekController {
String value() default "";

}

package com.iflytek.spring.annotation;


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/** 
 * @RequestMapping注解
 * @author: [email protected]
 * @created:Apr 6, 2018 8:07:40 PM 
 * @version: 1.0 
 * @lastModified
*/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IflytekRequestMapping {

String value() default "";

}

   package com.iflytek.spring.annotation;


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/** 
 * @RequestParam注解
 * @author: [email protected]
 * @created:Apr 6, 2018 8:08:20 PM 
 * @version: 1.0 
 * @lastModified
*/
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IflytekRequestParam {
String value() default "";

}


package com.iflytek.spring.annotation;


import java.lang.annotation.Documented; 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/** 
 * @Service注解
 * @author: [email protected]
 * @created:Apr 6, 2018 8:05:44 PM 
 * @version: 1.0 
 * @lastModified
*/


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IflytekService {
String value() default "";

}


--重点(所有重点代码都这个类中,很多思想都是依赖于反射)

package com.iflytek.spring.servlet;


import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


import com.iflytek.spring.annotation.IflytekAutowrited;
import com.iflytek.spring.annotation.IflytekController;
import com.iflytek.spring.annotation.IflytekRequestMapping;
import com.iflytek.spring.annotation.IflytekRequestParam;
import com.iflytek.spring.annotation.IflytekService;


/**
 * @author: [email protected]
 * @created:Apr 6, 2018 8:32:12 PM
 * @version: 1.0
 * @lastModified
 */
public class IflytekDisPatcherSevlet extends HttpServlet {
// 配置文件
private Properties properties = new Properties();
// 所有类名
private List<String> calssNames = new ArrayList<String>();
// ioc中容器的实例
private Map<String, Object> ioc = new HashMap<String, Object>();
// 请求方法映射
// private Map<String, Method> handlerMapping = new HashMap<String,
// Method>();


private List<Handler> handlerMapping = new ArrayList<Handler>();


/**
* 初始化
*/
@Override
public void init(ServletConfig config) throws ServletException {
// 1.加载配置文件
doloadConfig(config.getInitParameter("contextConfigLocation"));
// 2.根据配置文件扫描所有的类


doScaner(properties.getProperty("scanPackage"));


// 3.初始化所有类实例,放入ioc容器,也就是放入Map
try {
doIntance();
} catch (InstantiationException e) {


e.printStackTrace();
} catch (IllegalAccessException e) {


e.printStackTrace();
}
// 4.实现自动依赖注入
doAutowried();


// 5.初始化mapping
initHandleMapping();
}


private void initHandleMapping() {


String baseUrl = null;
if (ioc.isEmpty()) {
return;
}


for (Map.Entry<String, Object> entry : ioc.entrySet()) {
Class<?> clazz = entry.getValue().getClass();
// 不是Controller-就拜拜
if (!clazz.isAnnotationPresent(IflytekController.class)) {
continue;
}
// 判断有没有@IflytekRequestMapping注解
if (clazz.isAnnotationPresent(IflytekRequestMapping.class)) {
IflytekRequestMapping requestMapping = clazz.getAnnotation(IflytekRequestMapping.class);
baseUrl = requestMapping.value();
}
Method[] methods = clazz.getMethods();


for (Method method : methods) {
// 方法上如果没有加@IflytekRequestMapping
if (!method.isAnnotationPresent(IflytekRequestMapping.class)) {
continue;
}


IflytekRequestMapping requestMapping = method.getAnnotation(IflytekRequestMapping.class);
// String url = (baseUrl +
// requestMapping.value()).replaceAll("/+", "/");


String regex = ("/" + baseUrl + requestMapping.value()).replaceAll("/+", "/");
Pattern pattern = Pattern.compile(regex);
handlerMapping.add(new Handler(pattern, entry.getValue(), method));


}
}
}


private void doAutowried() {
if (ioc.isEmpty()) {
return;
}
for (Map.Entry<String, Object> entry : ioc.entrySet()) {
// 无论是什么访问权限,都要强制注入
Field[] fields = entry.getValue().getClass().getDeclaredFields();// 获取对象的所有属性
for (Field field : fields) {
// 判断字段上有没有@Autowried注解,有的话才注入
if (!field.isAnnotationPresent(IflytekAutowrited.class)) {
continue;
}
IflytekAutowrited autowrited = field.getAnnotation(IflytekAutowrited.class);
// 获取注解上有没有自定义值
String beanName = autowrited.value().trim();
// 如果没有自定义值,也就是null
if ("".equals(beanName)) {
beanName = field.getType().getName();
}
// 如果想要访问到私有的属性,我们要强制授权
// 不管你愿不愿意,我们都要给你注入
field.setAccessible(true);
try {
// 给@Autowrid设上了值
// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值
field.set(entry.getValue(), ioc.get(beanName));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}


}


private void doIntance() throws InstantiationException, IllegalAccessException {


if (calssNames != null)
// 通过反射机制构造对象


for (String calssName : calssNames) {


try {
Class<?> calzz = Class.forName(calssName);
// 初始化Ioc容器
// 只有头上有注解的才构造对象
// IOC key:
// value原则:
// 1.key默认类名小写
// 2.如果自定义了类名,则优先使用(@Service("AAA"))
// 3.如果注入是接口我们可以巧妙的用接口的类型作为key
if (calzz.isAnnotationPresent(IflytekController.class)) {
String className = calzz.getSimpleName();// 得到类名
String baneName = firstLowerCase(className);// 类名小写
ioc.put(baneName, calzz.newInstance());// 将反射生成的对象放入ioc容器
} else if (calzz.isAnnotationPresent(IflytekService.class)) {
IflytekService sevice = calzz.getAnnotation(IflytekService.class);
String beanNme = sevice.value();
// 如果自定义名称为空,就是默认首字母小写
if ("".equals(beanNme.trim())) {
beanNme = firstLowerCase(calzz.getSimpleName());// 类名小写
}
Object instance = calzz.newInstance();
ioc.put(beanNme, instance);
Class<?>[] interfaces = calzz.getInterfaces();
// 2.如果自定义了类名,则优先使用(@Service("AAA"))
for (Class<?> iface : interfaces) {
// 如果注入是接口我们可以巧妙的用接口的类型作为key
ioc.put(iface.getName(), instance);
}


} else {


continue;


}


} catch (ClassNotFoundException e) {
e.printStackTrace();
}


}


}


// 类名首字母转小写(此种方法高效)
private String firstLowerCase(String className) {
System.out.println(className + "-----className------");
char[] chars = className.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}


private void doScaner(String packageName) {
// 递归扫描所有的类


URL url = this.getClass().getClassLoader().getResource(packageName.replaceAll("\\.", "/"));
File classDir = new File(url.getFile());
for (File file : classDir.listFiles()) {
if (file.isDirectory()) {
doScaner(packageName + "." + file.getName());
} else {
String className = packageName + "." + file.getName().replace(".class", "");
calssNames.add(className);
}


}


}


private void doloadConfig(String config) {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(config);
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}


}
}
}


@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
doDispatch(req, resp);
} catch (Exception e) {
resp.getWriter().write("500 Server Exception");
e.printStackTrace();
}


}


// 等待请求
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取用户请求uri
// String url = req.getRequestURI();
// String contextPath = req.getContextPath();
// url = url.replace(contextPath, "").replaceAll("/+", "/");//
// replaceAll("/+",
// "/")表示把多个/一个转为(//-->/)
// 通过请求的url获取到要映射的方法
// if (!handlerMapping.containsKey(url)) {
// resp.getWriter().write("404 Not Found");
// return;
// }
// Method method = handlerMapping.get(url);
// method.invoke(obj, args);
// 获取method Url配置


try {
doDispatch(req, resp);
} catch (Exception e) {
e.printStackTrace();
}


}


private class Handler {
protected Object controller;
protected Method method;
protected Pattern pattern;
protected Map<String, Integer> paramIndexMaping;


public Handler(Pattern pattern, Object controller, Method method) {
this.pattern = pattern;
this.controller = controller;
this.method = method;
this.paramIndexMaping = new HashMap<String, Integer>();
putParamIndexMaping(method);
}


private void putParamIndexMaping(Method method) {
// 提取方法中加了注解的参数
Annotation[][] pa = method.getParameterAnnotations();


for (int i = 0; i < pa.length; i++) {
for (Annotation annotation : pa[i]) {
if (annotation instanceof IflytekRequestParam) {
String paramName = ((IflytekRequestParam) annotation).value();
if (!"".equals(paramName.trim())) {
paramIndexMaping.put(paramName, i);


}


}


}


}


Class<?>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
Class<?> type = parameterTypes[i];
if (type == HttpServletRequest.class || type == HttpServletResponse.class) {


paramIndexMaping.put(type.getName(), i);
}
}


}


}


private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
try {


Handler handler = getHandler(req);
if (handler == null) {
resp.getWriter().write("404 Not Found");
return;
}
// 获取参数列表
Class<?>[] parameters = handler.method.getParameterTypes();
// 保存所有自动赋值的参数值
Object[] parameValues = new Object[parameters.length];
Map<String, String[]> params = req.getParameterMap();
for (Entry<String, String[]> param : params.entrySet()) {
String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll(",\\s", ",");
// 如果找到匹配的对象,就填充参数


if (!handler.paramIndexMaping.containsKey(param.getKey())) {
continue;
}
int index = handler.paramIndexMaping.get(param.getKey());
parameValues[index] = convert(parameters[index], value);
}


// 设置方法中的 HttpServletRequest HttpServletResponse 对象


int reqIndex = handler.paramIndexMaping.get(HttpServletRequest.class.getName());


parameValues[reqIndex] = req;


int respIndex = handler.paramIndexMaping.get(HttpServletResponse.class.getName());
parameValues[respIndex] = resp;
handler.method.invoke(handler.controller, parameValues);


} catch (Exception e) {
e.printStackTrace();
}
}


/**
* @content:
* @author: [email protected]
* @created:Apr 7, 2018 1:48:03 AM
* @version: 1.0
* @lastModified
*/


private Object convert(Class<?> type, String value) {
if (Integer.class == type) {
return Integer.valueOf(value);


}
return value;
}


private Handler getHandler(HttpServletRequest req) {
if (handlerMapping.isEmpty()) {
return null;
}
String url = req.getRequestURI();
String contextPath = req.getContextPath();
// replaceAll("/+","/")表示把多个/一个转为(//-->/)
url = url.replace(contextPath, "").replaceAll("/+", "/");
for (Handler handler : handlerMapping) {
try {
Matcher matcher = handler.pattern.matcher(url);
// 如果没有就继续下一个匹配
if (matcher.matches()) {
continue;
}
return handler;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}


}

猜你喜欢

转载自blog.csdn.net/qq_31859365/article/details/79838589
今日推荐