`

手写spring mvc底层源码

阅读更多

手写源码之前先来了解几个概念:

1、spring IOC:控制反转,简单来说,就是tomcat在运行得时候创建了一个map,将那些有注解的对象存入这个map中,然后通过注解来获取这些对象供程序使用

2、DI:依赖注入,动态的向某个对象提供它需要的对象

3、DispatcherServlet:Spring MVC底层的具体实现,一般我们会选择默认提供的org.springframework.web.servlet.DispatcherServlet

 

如果想自己实现底层源码,那么就得自己手写DisPatcherServlet

1、首先自己定义几个注解,例如:

@Target(java.lang.annotation.ElementType.FIELD)//只能在类属性上使用

@Retention(RetentionPolicy.RUNTIME)//运行时调用

@Documented

public @interface TestAutowired {

String value() default "";

}

 

@Target(java.lang.annotation.ElementType.TYPE)//只能在类上使用

@Retention(RetentionPolicy.RUNTIME)//运行时调用

@Documented

public @interface TestController {

String value() default "";

}

 

@Target({java.lang.annotation.ElementType.TYPE,java.lang.annotation.ElementType.METHOD})//只能在类、方法上使用

@Retention(RetentionPolicy.RUNTIME)//运行时调用

@Documented

public @interface TestRequestMapping {

String value() default "";

}

 

@Target(java.lang.annotation.ElementType.PARAMETER)//只能在方法上使用

@Retention(RetentionPolicy.RUNTIME)//运行时调用

@Documented

public @interface TestRequestParam {

String value() default "";

}

 

@Target(java.lang.annotation.ElementType.TYPE)//只能在类上使用

@Retention(RetentionPolicy.RUNTIME)//运行时调用

@Documented

public @interface TestService {

String value() default "";

}

 

2、自己手写DispatcherServlet

public class DispatcherServlet extends HttpServlet{

 

List<String> classNames = new ArrayList<String>(); 

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

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

 

@Override

public void init(ServletConfig servletConfig) throws ServletException {

//1、扫描

scanPackage("com.wzy");

//2、实例化

doInstance();

//3、自动注入

doAutowired();

//4、方法映射,路径与方法对应

doUrlMapping();

}

 

public void doUrlMapping() {

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

Object instance = entry.getValue();

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

if(clazz.isAnnotationPresent(TestController.class)) {

//获取类的上的请求路径

TestRequestMapping classMapping = clazz.getAnnotation(TestRequestMapping.class);

String classPath = classMapping.value();

Method[] methods = clazz.getMethods();

for(Method method : methods) {

if(method.isAnnotationPresent(TestRequestMapping.class)) {

TestRequestMapping methodMapping= method.getAnnotation(TestRequestMapping.class);

String methodPath = methodMapping.value();

handlerMap.put(classPath+methodPath, method);

}

}

}

}

}

 

public void doAutowired() {

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

Object instance = entry.getValue();

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

if(clazz.isAnnotationPresent(TestController.class)) {

Field[] fields = clazz.getDeclaredFields();

for(Field field : fields) {

if(field.isAnnotationPresent(TestAutowired.class)) {

TestAutowired testAutowired = field.getAnnotation(TestAutowired.class);

String key = testAutowired.value();

Object obj = beans.get(key);

if(obj != null) {

//打开权限

field.setAccessible(true);

try {

field.set(instance, obj);

} catch (IllegalArgumentException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}else {

throw new RuntimeException(obj.getClass().getName()+"was not injection!");

}

}else {

continue;

}

}

}else {

continue;

}

}

}

 

public void doInstance() {

for(String className : classNames) {

String cn = className.replace(".class", "");

try {

Class<?> clazz = Class.forName(cn);

if(clazz.isAnnotationPresent(TestController.class)) {

//创建实例

Object instance = clazz.newInstance();

TestRequestMapping m1 = clazz.getAnnotation(TestRequestMapping.class);

beans.put(m1.value(), instance);

}else if(clazz.isAnnotationPresent(TestService.class)) {

//创建实例

Object instance = clazz.newInstance();

TestService m2 = clazz.getAnnotation(TestService.class);

beans.put(m2.value(), instance);

}else {

continue;

}

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (InstantiationException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

}

}

 

public 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 {

classNames.add(basePackage+"."+filePath.getName());

}

}

}

 

 

@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 {

String uri = req.getRequestURI();

String context = req.getContextPath();

String path = uri.replace(context, "");

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

TestController instance = (TestController) beans.get("/"+path.split("/")[1]);

Object[] args = hand(req, resp, method);

try {

method.invoke(instance, args);

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (IllegalArgumentException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

 

private static Object[] hand(HttpServletRequest request, HttpServletResponse response, Method method) {

//拿到当前待执行的方法有哪些参数

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

//根据参数的个数,new 一个参数的数组,将方法里的所有参数赋值到args来

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

int arg_i = 0;

int index = 0;

for(Class<?> paramClazz : paramClazzs) {

if(ServletRequest.class.isAssignableFrom(paramClazz)) {

args[arg_i++] = request;

}

if(ServletResponse.class.isAssignableFrom(paramClazz)) {

args[arg_i++] = response;

}

//判断有没有RequestParam注释

Annotation[] paramAns = method.getParameterAnnotations()[index];

if(paramAns.length > 0) {

for(Annotation annotation : paramAns) {

if(TestRequestParam.class.isAssignableFrom(paramAns.getClass())) {

TestRequestParam rp = (TestRequestParam) annotation;

args[arg_i++] = request.getParameter(rp.value());

}

}

}

index ++;

}

return args;

}

 

}

具体讲解下:

scanPackage方法,主要是遍历当前项目,将当前项目中的所有类都存于map中

doInstance方法,主要是遍历上述所有类,将类上有@TestController和@TestService的类进行实例化,然后存于另外的map中,key取@TestRequestMapping后的value值

doAutowired方法,主要是将所有带有@TestController类中的属性上带有@TestAutowired的这些属性从之前的map中获取实例,放进当前的属性中

doUrlMapping方法,将所有@TestController中方法上带有@TestRequestMapping的跟注解后的value路径进行对应

hand,获取当前请求对应的方法中有哪些参数

 

注意:本文没有提到其实在@TestService注解的类下其实也可有@TestAutoWired注解的属性,这个其实可以根据上面的逻辑进行扩展;还有当某个注解后没有value属性值的话,key值该怎么取,可以先获取当前类、属性的名称,然后将首字母小写,将其作为key就可以了

 

附上本人练习项目控制层和服务层:

@TestController

@TestRequestMapping("/test")

public class OrderController {

 

@TestAutowired("orderServiceImpl")

private OrderService orderService;

 

@TestRequestMapping("/get")

public String get(@TestRequestParam("name")String name, @TestRequestParam("age")int age) {

return orderService.query(name, age);

}

 

}

 

@TestService("orderServiceImpl")

public class OrderServiceImpl implements OrderService{

 

public String query(String name, int age) {

return "[name:"+name+",age"+age+"]";

}

 

}

 转发表明来源

 

 

 

分享到:
评论

相关推荐

    最新springmvc源码分析与实战

    最新springmvc源码分析与实战,绝对超值,亲测,高清,完整标签,已读。

    Spring+Mvc手写基本源码+思维导图,快速理解spring+mvc原理

    Spring MVC 是一款强大的Java Web开发框架,用于构建可...手写Spring MVC源码是一个挑战性的实践过程,但能带来深入的理解和技能提升。在这个过程中,思维导图是一个有效的辅助工具,帮助我们梳理和可视化整个流程。

    手写Spring源码+MVC架构

    手写Spring源码+MVC架构

    仿 Spring 手写 MVC 框架_源码.rar

    本教程将带你深入理解Spring MVC的核心原理,并通过仿照Spring MVC,手写一个简单的MVC框架来深化理解。 MVC模式是软件工程中的一种设计模式,用于分离业务逻辑(Model)、用户界面(View)和数据控制(Controller...

    Spring MVC应用开源架构源码2021.pdf

    Spring MVC源码深度剖析部分,将会详细解读Spring MVC框架的内部实现机制。核心组件如DispatcherServlet、HandlerMapping、HandlerAdapter等,每个组件的职责和如何相互协作,以及源码中对各种复杂场景的处理。 SSM...

    spring源码合集spring源码合集

    8. **模拟Spring底层原理**:"02-手写模拟Spring底层原理-周瑜"和"01-Spring底层核心原理解析-周瑜"提供了从零开始构建类似Spring框架的实践机会,通过动手实践加深对Spring核心机制的理解。 这些源码解析资料覆盖...

    手写Spring源码.rar

    本压缩包"手写Spring源码.rar"可能包含了一份详尽的、逐步实现Spring核心功能的源代码分析,这对于理解Spring的工作原理和提升开发者技能非常有帮助。下面,我们将深入探讨Spring框架的一些关键知识点。 1. **依赖...

    【预习资料】一步一步手绘Spring MVC运行时序图.docx

    本课程旨在深入理解Spring MVC的运行机制、源码分析以及最佳实践,适合对Spring使用有一定基础但希望进一步提升技能的开发者。 首先,了解Spring MVC的请求处理流程至关重要。当一个HTTP请求到达服务器,Spring MVC...

    【预习资料】一步一步手绘Spring MVC运行时序图.pdf

    推荐的参考书籍《Spring 5核心原理与30个类手写实战》提供了实践操作的指导。 通过这门课程的学习,开发者不仅能掌握Spring MVC的执行流程,还能深入理解设计模式和软件工程的思想,提升解决实际问题的能力。请注意...

    Spring mvc + Spring + Spring jdbc 整合 demo.rar

    【标题】"Spring mvc + Spring + Spring jdbc 整合 demo.rar" 提供了一个整合了Spring MVC、Spring和Spring JDBC的示例项目。这个压缩包包含了一整套使用Java EE技术栈开发的Web应用程序,主要关注于后端数据处理和...

    手把手教你手写SpringMvc框架(附源码)

    Java编程的学习,一直以来都是一门非常重量级的学习科目,本教程以项目实战为导向,帮助广大学员手把手教学,本课程从无到有,循序渐进的手写mvc框架,由于官方的框架比较复杂,为了让同学们能够学懂,先从简单地MVC...

    02-01-08-用30个类高仿真提炼纯手写Spring框架V2.0之MVC1

    【Spring 框架模拟构建】:本课程旨在深度解析并模拟实现Spring框架的核心部分,特别是Spring MVC,通过创建30个类来构建一个高度仿真的简易版Spring框架。这将帮助开发者深入理解Spring的系统架构和实现原理,以及...

    手写spring1.0

    本指南将深入探讨“手写Spring1.0”这一主题,旨在帮助初学者理解Spring的核心原理,为后续学习Spring MVC和更高级的版本打下坚实的基础。 首先,我们要明确Spring1.0是Spring框架的早期版本,虽然功能相较于现在的...

    京东T5级大牛带你解读Spring核心源码——1小时手写SpringMVC~

    ### Spring核心源码解读与手动实现SpringMVC #### 一、Spring框架简介 Spring框架是由Rod Johnson在2004年发起的一个开源项目,它是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器。Spring框架的核心特性包括:...

    spring、 spring mvc、 mybatis 开发的java客户关系管理系统,前端采用easyui编写

    在本项目中,开发者利用了Spring、Spring MVC和MyBatis三大核心框架构建了一个完整的Java客户关系管理系统(CRM)。这是一个常见的技术栈组合,用于构建高效、可维护的企业级Web应用。接下来,我们将深入探讨这三个...

    821442150396773手写Spring.zip

    标题 "821442150396773手写Spring.zip" 提示我们这可能是一个关于自己实现Spring框架的项目或者教程。Spring是一个广泛使用的Java企业级应用开发框架,它以依赖注入(Dependency Injection, DI)为核心,提供面向切...

    手写MVC框架开源架构源码2021.pdf

    在本篇内容中,我们将探讨如何手写一个简单的MVC框架,主要基于提供的代码片段,这些片段涉及到核心的注解如`@LagouController`、`@LagouService`、`@LagouAutowired`以及`@LagouRequestMapping`,以及一个基础的...

    用300行代码手写Spring V1.0版本

    本文将通过分析标题"用300行代码手写Spring V1.0版本"和描述,探讨Spring的基本设计理念和实现机制。 首先,Spring的核心是IoC容器,它负责管理对象的生命周期和依赖关系。在300行代码的简化版本中,我们将看到如何...

    spring+mybatis企业应用实战官方源码下载

    spring+mybatis企业应用实战官方源码下载,含光盘所有内容,除了官方的02-14讲义的源码外,13张的sql我也手写了,且综合资源压缩资源359M,资源未做任何精简,myeclispe和eclipse能直接引用运行。

Global site tag (gtag.js) - Google Analytics