手写源码之前先来了解几个概念:
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源码分析与实战,绝对超值,亲测,高清,完整标签,已读。
Spring MVC 是一款强大的Java Web开发框架,用于构建可...手写Spring MVC源码是一个挑战性的实践过程,但能带来深入的理解和技能提升。在这个过程中,思维导图是一个有效的辅助工具,帮助我们梳理和可视化整个流程。
手写Spring源码+MVC架构
本教程将带你深入理解Spring MVC的核心原理,并通过仿照Spring MVC,手写一个简单的MVC框架来深化理解。 MVC模式是软件工程中的一种设计模式,用于分离业务逻辑(Model)、用户界面(View)和数据控制(Controller...
Spring MVC源码深度剖析部分,将会详细解读Spring MVC框架的内部实现机制。核心组件如DispatcherServlet、HandlerMapping、HandlerAdapter等,每个组件的职责和如何相互协作,以及源码中对各种复杂场景的处理。 SSM...
8. **模拟Spring底层原理**:"02-手写模拟Spring底层原理-周瑜"和"01-Spring底层核心原理解析-周瑜"提供了从零开始构建类似Spring框架的实践机会,通过动手实践加深对Spring核心机制的理解。 这些源码解析资料覆盖...
本压缩包"手写Spring源码.rar"可能包含了一份详尽的、逐步实现Spring核心功能的源代码分析,这对于理解Spring的工作原理和提升开发者技能非常有帮助。下面,我们将深入探讨Spring框架的一些关键知识点。 1. **依赖...
本课程旨在深入理解Spring MVC的运行机制、源码分析以及最佳实践,适合对Spring使用有一定基础但希望进一步提升技能的开发者。 首先,了解Spring MVC的请求处理流程至关重要。当一个HTTP请求到达服务器,Spring MVC...
推荐的参考书籍《Spring 5核心原理与30个类手写实战》提供了实践操作的指导。 通过这门课程的学习,开发者不仅能掌握Spring MVC的执行流程,还能深入理解设计模式和软件工程的思想,提升解决实际问题的能力。请注意...
【标题】"Spring mvc + Spring + Spring jdbc 整合 demo.rar" 提供了一个整合了Spring MVC、Spring和Spring JDBC的示例项目。这个压缩包包含了一整套使用Java EE技术栈开发的Web应用程序,主要关注于后端数据处理和...
Java编程的学习,一直以来都是一门非常重量级的学习科目,本教程以项目实战为导向,帮助广大学员手把手教学,本课程从无到有,循序渐进的手写mvc框架,由于官方的框架比较复杂,为了让同学们能够学懂,先从简单地MVC...
【Spring 框架模拟构建】:本课程旨在深度解析并模拟实现Spring框架的核心部分,特别是Spring MVC,通过创建30个类来构建一个高度仿真的简易版Spring框架。这将帮助开发者深入理解Spring的系统架构和实现原理,以及...
本指南将深入探讨“手写Spring1.0”这一主题,旨在帮助初学者理解Spring的核心原理,为后续学习Spring MVC和更高级的版本打下坚实的基础。 首先,我们要明确Spring1.0是Spring框架的早期版本,虽然功能相较于现在的...
### Spring核心源码解读与手动实现SpringMVC #### 一、Spring框架简介 Spring框架是由Rod Johnson在2004年发起的一个开源项目,它是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器。Spring框架的核心特性包括:...
在本项目中,开发者利用了Spring、Spring MVC和MyBatis三大核心框架构建了一个完整的Java客户关系管理系统(CRM)。这是一个常见的技术栈组合,用于构建高效、可维护的企业级Web应用。接下来,我们将深入探讨这三个...
标题 "821442150396773手写Spring.zip" 提示我们这可能是一个关于自己实现Spring框架的项目或者教程。Spring是一个广泛使用的Java企业级应用开发框架,它以依赖注入(Dependency Injection, DI)为核心,提供面向切...
在本篇内容中,我们将探讨如何手写一个简单的MVC框架,主要基于提供的代码片段,这些片段涉及到核心的注解如`@LagouController`、`@LagouService`、`@LagouAutowired`以及`@LagouRequestMapping`,以及一个基础的...
本文将通过分析标题"用300行代码手写Spring V1.0版本"和描述,探讨Spring的基本设计理念和实现机制。 首先,Spring的核心是IoC容器,它负责管理对象的生命周期和依赖关系。在300行代码的简化版本中,我们将看到如何...
spring+mybatis企业应用实战官方源码下载,含光盘所有内容,除了官方的02-14讲义的源码外,13张的sql我也手写了,且综合资源压缩资源359M,资源未做任何精简,myeclispe和eclipse能直接引用运行。