返回

Spring源码分析之大结局-手写springmvc

发布时间:2022-12-06 13:06:27 198
# webkit# java# spring# java# 扫描

1.创建一个maven工程,并生成web工程

Spring源码分析之大结局-手写springmvc_java

 

pom文件如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.caojiulu</groupId>
<artifactId>jiulu-springmvc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>

<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0-alpha-1</version>
<scope>provided</scope>
</dependency>
</dependencies>

</project>

2.创建对应的注解:

package com.caojiulu.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;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JiuluController {

String value() default "";

}
package com.caojiulu.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;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JiuluAutowired {

String value() default "";

}
package com.caojiulu.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;

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JiuluRequestMapping {

String value() default "";

}
package com.caojiulu.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;

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JiuluRequestParam {

String value() default "";

}
package com.caojiulu.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;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JiuluService {

String value() default "";

}

 

3.创建接口以及实现类:

package com.caojiulu.service;

public interface CaojiuluService {


String query(String name,String age);
}
package com.caojiulu.service.impl;

import com.caojiulu.annotation.JiuluService;
import com.caojiulu.service.CaojiuluService;

@JiuluService("CaojiuluServiceImpl")
public class CaojiuluServiceImpl implements CaojiuluService{

@Override
public String query(String name, String age) {
return "{name="+name+",age="+age+"}";
}


}

 

2.修改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" version="2.5">
<display-name>jiulu-springmvc</display-name>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>com.caojiulu.service.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

3.编写核心DispatcherServlet

package com.caojiulu.service.servlet;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
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 javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.caojiulu.annotation.JiuluAutowired;
import com.caojiulu.annotation.JiuluController;
import com.caojiulu.annotation.JiuluRequestMapping;
import com.caojiulu.annotation.JiuluService;
import com.caojiulu.controller.CaoJiuluController;
import com.caojiulu.handlerAdapter.HandlerAdapterService;

public class DispatcherServlet extends HttpServlet{

List classNames = new ArrayList();
Map<String, Object> beans = new HashMap<String, Object>();
Map<String, Object> handlerMap = new HashMap<String, Object>();
@Override
public void init(ServletConfig config) throws ServletException {
//扫描package
scanPackage("com.caojiulu");

System.out.println(Arrays.asList(classNames));
//实例化
instance();
for (Map.Entry<String, Object> entry : beans.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
//ioc
ioc();
//建立path和method的映射关系
handlerMapping();

for (Map.Entry<String, Object> entry : handlerMap.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}


private void handlerMapping() {
if(beans.entrySet().size()<=0){
System.out.println("没有类的实例化");
return ;
}

for (Map.Entry<String, Object> entry : beans.entrySet()) {

Object instance = entry.getValue();
Class<?> clazz = instance.getClass();

if(clazz.isAnnotationPresent(JiuluController.class)){
JiuluRequestMapping jiuluRequestMappingclass = clazz.getAnnotation(JiuluRequestMapping.class);

String classPath = jiuluRequestMappingclass.value();

Method[] methods = clazz.getMethods();
for (Method method : methods) {
if(method.isAnnotationPresent(JiuluRequestMapping.class)){

JiuluRequestMapping annotation = method.getAnnotation(JiuluRequestMapping.class);
String value = annotation.value();
handlerMap.put(classPath+value, method);
}else{
continue;
}
}
}

}


}


private void ioc() {
if(classNames.size()<=0){
System.out.println("包扫描失败");
return ;
}

for (Map.Entry<String, Object> entry : beans.entrySet()) {
Object value = entry.getValue();
//获取对象的类型
Class<?> class1 = value.getClass();
if(class1.isAnnotationPresent(JiuluController.class)){
Field[] fields = class1.getDeclaredFields();
for (Field field : fields) {
if(field.isAnnotationPresent(JiuluAutowired.class)){
JiuluAutowired jiuluAutowired = field.getAnnotation(JiuluAutowired.class);
//field.set
String value2 = jiuluAutowired.value();
field.setAccessible(true);
try {
field.set(value, beans.get(value2));
} catch (IllegalArgumentException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
continue;
}
}
}else{
continue;
}

}

}


private void instance() {
if(classNames.size()<=0){
System.out.println("包扫描失败");
return ;
}

for (String className : classNames) {
String cn = className.replace(".class", "");

try {
Class<?> clazz = Class.forName(cn);
if(clazz.isAnnotationPresent(JiuluController.class)){
Object newInstance = clazz.newInstance();
JiuluRequestMapping annotation = clazz.getAnnotation(JiuluRequestMapping.class);
String value = annotation.value();
beans.put(value, newInstance);
}else if(clazz.isAnnotationPresent(JiuluService.class)){
Object newInstance = clazz.newInstance();
JiuluService annotation = clazz.getAnnotation(JiuluService.class);
String value = annotation.value();
beans.put(value, newInstance);
}else{
continue;
}



} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//jiulu-springmvc/jiulu/query
String requestURI = request.getRequestURI();

// /jiulu-springmvc
String contextPath = request.getContextPath();
String path = requestURI.replace(contextPath, "");

Method method = (Method)handlerMap.get(path);

//拿到控制类
CaoJiuluController jiuluController = (CaoJiuluController) beans.get("/"+path.split("/")[1]);

HandlerAdapterService ha = (HandlerAdapterService) beans.get("jiuluHandlerAdapter");

Object[] args = ha.hand(request, response, method, beans);
try {
method.invoke(jiuluController, args);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}


private void scanPackage(String filePath) {
URL resource = this.getClass().getClassLoader().getResource("/"+filePath.replace(".", "/"));
String path = resource.getPath();
File file = new File(path);
String[] list = file.list();
for (String string : list) {
File file2 = new File(path+"/"+string);
if(file2.isDirectory()){
scanPackage(filePath +"."+string);
}else{
classNames.add(filePath+"."+file2.getName());
}
}
}



}

4.策略模式处理请求参数

package com.caojiulu.argumentResolver;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface ArgumentResolver {

public boolean support(Class<?> type, int paramIndex, Method method);

//参数解析方法
public Object argumentResolver(HttpServletRequest request,
HttpServletResponse response, Class<?> type,
int paramIndex,//参数索引下坐标,有很多注解,你得知道是哪个参数的注解,每个参数的索引顺序不一样
Method method);

}
package com.caojiulu.argumentResolver;

import java.lang.reflect.Method;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.caojiulu.annotation.JiuluService;
@JiuluService("httpServletRequestArgumentResolver")
public class HttpServletRequestArgumentResolver implements ArgumentResolver{

@Override
public boolean support(Class<?> type, int paramIndex, Method method) {
return ServletRequest.class.isAssignableFrom(type);
}

@Override
public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
int paramIndex, Method method) {
return request;
}

}
package com.caojiulu.argumentResolver;

import java.lang.reflect.Method;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.caojiulu.annotation.JiuluService;

@JiuluService("httpServletResponseArgumentResolver")
public class HttpServletResponseArgumentResolver implements ArgumentResolver{

@Override
public boolean support(Class<?> type, int paramIndex, Method method) {
return ServletResponse.class.isAssignableFrom(type);
}

@Override
public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
int paramIndex, Method method) {
return response;
}

}
package com.caojiulu.argumentResolver;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.caojiulu.annotation.JiuluRequestParam;
import com.caojiulu.annotation.JiuluService;

@JiuluService("requestParamArgumentResolver")
public class RequestParamArgumentResolver implements ArgumentResolver{

@Override
public boolean support(Class<?> type, int paramIndex, Method method) {
Annotation[][] parameterAnnotations = method.getParameterAnnotations();

Annotation[] annotations = parameterAnnotations[paramIndex];
for (Annotation annotation : annotations) {
if(JiuluRequestParam.class.isAssignableFrom(annotation.getClass())){
return true;
}
}
return false;
}

@Override
public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
int paramIndex, Method method) {
Annotation[][] parameterAnnotations = method.getParameterAnnotations();

Annotation[] annotations = parameterAnnotations[paramIndex];
for (Annotation annotation : annotations) {
if(JiuluRequestParam.class.isAssignableFrom(annotation.getClass())){
JiuluRequestParam jiuluRequestParam = (com.caojiulu.annotation.JiuluRequestParam) annotation;
String value = jiuluRequestParam.value();
return request.getParameter(value);
}
}
return null;
}

}

5.处理器的实现

package com.caojiulu.handlerAdapter;

import java.lang.reflect.Method;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface HandlerAdapterService {

public Object[] hand(HttpServletRequest request,//拿request请求里的参数
HttpServletResponse response,Method method,Map<String,Object> beans);

}
package com.caojiulu.handlerAdapter;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.caojiulu.annotation.JiuluService;
import com.caojiulu.argumentResolver.ArgumentResolver;
@JiuluService("jiuluHandlerAdapter")
public class JiuluHandlerAdapter implements HandlerAdapterService{

@Override
public Object[] hand(HttpServletRequest request, HttpServletResponse response, Method method,
Map<String, Object> beans) {


Class<?>[] parameterTypes = method.getParameterTypes();

Object[] args = new Object[parameterTypes.length];

Map<String, Object> argumentResolvers = getBeansOfType(beans,ArgumentResolver.class);
int paramIndex = 0 ;
int i = 0;
for (Class<?> param : parameterTypes) {
for (Map.Entry<String, Object> entry : argumentResolvers.entrySet()) {
ArgumentResolver ar = (ArgumentResolver) entry.getValue();
if(ar.support(param, paramIndex, method)){
args[i++] = ar.argumentResolver(request, response, param, paramIndex, method);
}
}
paramIndex ++;
}

return args;
}

private Map<String, Object> getBeansOfType(Map<String, Object> beans, Class class1) {

Map<String, Object> resultBeans = new HashMap<String,Object>();

for (Map.Entry<String, Object> entry : beans.entrySet()) {
Class<?>[] interfaces = entry.getValue().getClass().getInterfaces();
if(interfaces!=null & interfaces.length>0){
for (Class<?> class2 : interfaces) {
if(class2.isAssignableFrom(class1)){
resultBeans.put(entry.getKey(), entry.getValue());
}
}
}
}

return resultBeans;
}



}

6.运行测试情况:

Spring源码分析之大结局-手写springmvc_java_02

Spring源码分析之大结局-手写springmvc_java_03

完成手写springmvc!

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线