之前一直对spring mvc 底层的实现原理狠挠头,直到网上听了一节课,花了一下午的时间跟着视频简单的实现了spring mvc。现整理下心得体会。
个人对spring mvc的理解是 spring mvc = servlet + spring。其底层的实现技术主要是 自定义注解+反射。想要实现spring mvc 首先要先把spring mvc中常用的自定义注解整理实现出来。
1:常用注解
(1):作用于Controller类上的@Controller 注解
/**
* Created by zs.xu on 2020/8/13.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XzsController {
String value() default "";
}
(2):作用于Service实现类上的@Service注解
/**
* Created by zs.xu on 2020/8/13.
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XzsService {
String value() default "";
}
(3):作用于Controller类和其方法上用于映射路径的@RequestMapping注解
/**
* Created by zs.xu on 2020/8/13.
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XzsRequestMapping {
String value() default "";
}
(4):作用于用于自动装配实现类的@Autowired 注解
/**
* Created by zs.xu on 2020/8/13.
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XzsAutowired {
String value() default "";
}
(5):作用于Controller方法上用于接收请求参数的@RequestParam注解
/**
* Created by zs.xu on 2020/8/13.
*/
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XzsRequestParam {
String value() default "";
}
2:底层核心方法都是在Servlet中实现的,所以项目在启动时,要根据servlet完成以下动作
2.1:项目启动时servlet要初始化的一些数据
//用于保存所有的类的全路径名
List<String> classList = new ArrayList<String>();
//用于保存所有的bean实例 key:注解的值,value:对象 的 实例)
Map<String,Object> beanMap = new HashMap<String, Object>();
//用于保存Controller里的url对呀的方法 key:类上加方法上的RequestMapping的值,value:对呀方法
Map<String,Object> urlMap = new HashMap<String, Object>();
public void init(ServletConfig config){
//1:扫描出项目下所有的class文件,并存对应类的全路径名,以便于后面用反射实例化对象。
scanPackage("com.xzs");
//2: 根据第一步扫描出的class,配合类对应使用的注解,映射出类对应的实现类 保存到map(key:注解的值,value:对象 的 实例)中。
doInstance();
//3:把service实例注入到Controller对象中的service属性
doIoc();
//4:把Controller的方法与@RequestMapping的value做映射关系,并存下来
buildUrlMapping();
}
(1):扫描出项目下所有的class文件,并存对应类的全路径名,以便于后面用反射实例化对象。
//扫描"com.xzs"路径下文件
private void scanPackage(String basePackage) {
URL url = this.getClass().getClassLoader().getResource("/"+basePackage.replaceAll("\\.","/"));
String fileStr = url.getFile();
File file = new File(fileStr);
String[] filesStr = file.list();
for (String path : filesStr){
//筛选出文件
File filePath = new File(fileStr+path);
if (filePath.isDirectory()){
scanPackage( basePackage+"."+path);
}else{
//找到class类
classList.add(basePackage+"."+filePath.getName());//内容是全类名路径
}
}
}
(2):根据第一步扫描出的class,配合类对应使用的注解,映射出类对应的实现类 保存到map(key:注解的值,value:对象 的 实例)中。
//根据扫描出的list全类名,进行实例化
private void doInstance() {
if (null==classList ||classList.size()<=0){
System.out.println("包扫描失败");
return;
}
for (String className : classList){
className = className.replace(".class","");
try {
Class<?> classZ = Class.forName(className);
//判断有没有用注解
if (classZ.isAnnotationPresent(XzsController.class)){
Object instance = classZ.newInstance();//创建控制类实例化对象
XzsRequestMapping requestMapping = classZ.getAnnotation(XzsRequestMapping.class);
String rmValue = requestMapping.value();
beanMap.put(rmValue,instance);
}else if (classZ.isAnnotationPresent(XzsService.class)){
XzsService service = classZ.getAnnotation(XzsService.class);
Object instance = classZ.newInstance();
beanMap.put(service.value(),instance);
}else{
continue;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
(3):把service实例注入到Controller对象中的service属性
//把service注入到controller控制层
private void doIoc() {
if (beanMap.entrySet().size() <= 0){
System.out.println("没有一个被实例化的类");
}
for (Map.Entry<String, Object> entry: beanMap.entrySet()) {
Object instance = entry.getValue();
Class<?> clasz = instance.getClass();
if (clasz.isAnnotationPresent(XzsController.class)){
//@XzsAutowired("LYTService")
//private LYTService lytService;
Field[] fields = clasz.getDeclaredFields();
for (Field field:fields){
//判断属性值上有没有注解
if (field.isAnnotationPresent(XzsAutowired.class)){
XzsAutowired annotation = field.getAnnotation(XzsAutowired.class);
String key = annotation.value();//"LYTService"
field.setAccessible(true);//private类型 的属性 注入不进去,需要放开权限
//设置值
try {
field.set(instance,beanMap.get(key));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}else{
continue;
}
}
}
}
}
(4):把Controller的方法与@RequestMapping的value做映射关系,并存下来
//4:url 映射 把方法和请求地址做关联 ;;;/xzs/select 找到对应的方法
private void buildUrlMapping() {
if (beanMap.entrySet().size() <= 0){
System.out.println("没有一个被实例化的类");
}
for (Map.Entry<String, Object> entry : beanMap.entrySet()) {
Class<?> clasz = entry.getValue().getClass();
if (clasz.isAnnotationPresent(XzsController.class)){
XzsRequestMapping controllerMapping = clasz.getAnnotation(XzsRequestMapping.class);
String controllerUrl = controllerMapping.value();//拿到了---》/xzs
Method[] methods = clasz.getMethods();
for (Method method:methods){
//判断属性值上有没有注解
if (method.isAnnotationPresent(XzsRequestMapping.class)){
XzsRequestMapping methodMapping = method.getAnnotation(XzsRequestMapping.class);
String methodUrl = methodMapping.value();//拿到了---》/select
//controllerUrl+methodUrl == /xzs/select
//key:url路径 ,value:待执行的方法
urlMap.put(controllerUrl+methodUrl,method);
}else{
continue;
}
}
}
}
}
2.1:Servlet重新继承的HttpServlet的 doGet(),doPost()方法,经过处理,拿到请求路径 ,找到请求路径对应的Controller方法,解析出对应的请求参数然后执行对应的方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//根据路径拿到对应的方法
//1:获取请求路径--
String requestURI = req.getRequestURI();
String contextPath = req.getContextPath();
String path = requestURI.replace(contextPath, "");//urlMap的key
//2:拿到方法
Method method = (Method)urlMap.get(path);
String[] split = path.split("/");
String controllerPath=null!=split&&split.length>1?"/"+split[1]:"";
//3:拿到方法对应的控制类
Object o = beanMap.get(controllerPath);
//4:参数处理
Object arg[] = hand(req,resp,method);
try {
method.invoke(o,arg);
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
//获取方法中的参数
private static Object[] hand(HttpServletRequest request, HttpServletResponse response,Method method){
//拿到当前执行方法有哪些参数
Class<?>[] paramClazzs = method.getParameterTypes();
//根据参数个数,new一个参数的数组,将方法里的所有参数赋值大agrs中
Object[] args = new Object[paramClazzs.length];
int args_i = 0;
int index = 0;
for (Class<?> paramClazz : paramClazzs) {
if(ServletRequest.class.isAssignableFrom(paramClazz)){
args[args_i++] = request;
}
if(ServletResponse.class.isAssignableFrom(paramClazz)){
args[args_i++] = response;
}
Annotation[] paramAns = method.getParameterAnnotations()[index];
if(paramAns.length>0){
for (Annotation paramAn : paramAns) {
if(XzsRequestParam.class.isAssignableFrom(paramAn.getClass())){
XzsRequestParam mp = (XzsRequestParam) paramAn;
//找到注解里的name和value
args[args_i++] = request.getParameter(mp.value());
}
}
}
index++;
}
return args;
}