手写springmvc框架ioc容器(简易版),实现实体类参数接收,并实现基于yaml配置文件
基于注解yaml配置手动实现简单的springmvc,实现bean注入功能,mvc实体类参数接收
-
- 项目github地址:https://github.com/kongGe55/spring-mvc-test
- 整个项目只依赖了javaweb相关jar包
- 不完善的地方
- 使用方法和springmvc一样,只不过配置文件要在resource下,名称application.yaml
- 实现效果
-
- 实体类参数注入效果
- bean自动注入效果
- 基本包
- 下面是相关代码,具体项目可以到gihub下载https://github.com/kongGe55/spring-mvc-test
-
- 首先是相关注解
- 然后是核心的DispatcherServlet相关代码
- BeanFactory bean工厂接口
- SpringMvcBeanFactory工厂类
- handler处理器接口
- HttpRequestHandler处理器类
- HandlerMapping处理器映射类
项目github地址:https://github.com/kongGe55/spring-mvc-test
整个项目只依赖了javaweb相关jar包
junit junit 4.11 test org.apache.tomcat servlet-api 6.0.29 provided org.yaml snakeyaml 1.17 com.fasterxml.jackson.core jackson-core 2.9.8 com.fasterxml.jackson.core jackson-databind 2.9.8
不完善的地方
- 实体类参数接受只支持String类型和Interger,后期可以加上其他参数类型接收,支持类型有限;
- 只支持注解
- 还很多不完善的地方望指正,我也是在学习反射的使用
使用方法和springmvc一样,只不过配置文件要在resource下,名称application.yaml
配置web.xml
Archetype Created Web Application DispacherServlet com.ji.spring.springmvc.servlet.DispatcherServlet 1 DispacherServlet /
applicetion配置
springmvc : application :# 要扫描的包名 scanPackage : com.ji.test
实现效果
实体类参数注入效果
实体类
public class User {private String name;private Integer age;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "User [name=" + name + ", age=" + age + "]";}}
测试controller
@Controller@RequestMapping("test")public class TestController { @AutoWired private TestService testService; @RequestMapping("demo") public void success(){ System.out.println("访问成功!111111111111111111111"); } @RequestMapping("user") public User user(@RequestParam("age")Integer i,@RequestParam("name") String name ,User user) { System.out.println(user); System.out.println(i); System.out.println(); System.out.println(name); return user; }}
访问效果
bean自动注入效果
controller
@Controller@RequestMapping("user")public class UserController { @AutoWired private UserService userService; @RequestMapping("findUser") public List findUser(HttpServletResponse response) throws IOException { List list = userService.findUser(); return list; }}
这里返回数据自动进行了处理
Service
@Component("userService") //也可以直接用@Service注解public class UserService { public List findUser(){ User user1 = new User(); user1.setAge(23); user1.setName("测试1"); User user2 = new User(); user2.setAge(23); user2.setName("测试2"); User user3 = new User(); user3.setAge(55); user3.setName("测试3"); List list = new ArrayList(); list.add(user1); list.add(user2); list.add(user3); return list; }}
访问效果
基本包
下面是相关代码,具体项目可以到gihub下载https://github.com/kongGe55/spring-mvc-test
首先是相关注解
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface AutoWired { String value() default "";}------------------------------------------------@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Component { String value();}--------------------------------------------------------@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Service {}----------------------------------------------------------------@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Controller {}------------------------------------------------------------@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface RequestMapping { String value() default "";}--------------------------------------- @Target(ElementType.PARAMETER)@Retention(RetentionPolicy.RUNTIME)public @interface RequestParam { String value() default "";}
然后是核心的DispatcherServlet相关代码
package com.ji.spring.springmvc.servlet;import com.ji.spring.core.annotation.AutoWired;import com.ji.spring.core.annotation.Component;import com.ji.spring.core.annotation.Service;import com.ji.spring.springmvc.annotation.Controller;import com.ji.spring.core.bean.SpringMvcBeanFactory;import com.ji.spring.core.bean.BeanFactory;import com.ji.spring.springmvc.annotation.RequestMapping;import com.ji.spring.springmvc.annotation.RequestParam;import org.yaml.snakeyaml.Yaml;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.*;import java.lang.annotation.Annotation;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.net.URL;import java.security.KeyStore;import java.util.*;public class DispatcherServlet extends HttpServlet { private List classNameList = new ArrayList(); private Map handlerMappings = new HashMap(); HttpRequestHandler httpRequestHandler; @Override public void init() throws ServletException { //扫描包下的类 try { initClassNameList(); } catch (FileNotFoundException e) { System.out.println("没有找到配置文件"); } //初始化bean容器 initBeans(); //初始化属性注入 initWired(); //初始化HandlerMapping initHandlerMapping(); httpRequestHandler = new HttpRequestHandler(); } private void initHandlerMapping() { //遍历bean容器 SpringMvcBeanFactory beanFactory = (SpringMvcBeanFactory) SpringMvcBeanFactory.getBeanFactory(); Set set = beanFactory.keySet(); for (String key:set){ Object bean = beanFactory.getBean(key); Class beanClass = bean.getClass(); if (beanClass.isAnnotationPresent(Controller.class)){ //如果是controller String url = "/"; if (beanClass.isAnnotationPresent(RequestMapping.class)){ //判断类上RequestMapping路径 RequestMapping requestMapping = (RequestMapping) beanClass.getAnnotation(RequestMapping.class); String tem = requestMapping.value(); url = url+tem+"/"; } //判断方法上RequestMapping路径 Method[] methods = beanClass.getDeclaredMethods(); for (Method method:methods){ if (method.isAnnotationPresent(RequestMapping.class)){ RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class); String s = methodAnnotation.value(); String url_tem = url; url_tem += s; url_tem.replaceAll("//", "/"); HandlerMapping handlerMapping = new HandlerMapping(bean,method); handlerMappings.put(url_tem,handlerMapping); } } } } } private Object[] searchParam(Method method, HttpServletRequest req, HttpServletResponse resp) { //获取方法上的参数类型并生成参数 Class[] parameterTypes = method.getParameterTypes(); Object[] args = new Object[parameterTypes.length]; Annotation[][] parameterAnnotations = method.getParameterAnnotations(); for (int j=0;j<parameterTypes.length;j++){ String simpleName = parameterTypes[j].getSimpleName(); switch (simpleName){ case "HttpServletRequest": args[j] = req; break; case "HttpServletResponse": args[j]=resp; break; case "String": RequestParam requestParam = getRequestParamAnnotationByIndex(parameterAnnotations,j); String param_Name = requestParam.value(); String str = req.getParameter(param_Name); if (!isEmpty(str)){ args[j] = str; } break; case "Integer": RequestParam requestParam1 = getRequestParamAnnotationByIndex(parameterAnnotations,j); String param_Name1 = requestParam1.value(); String parameter = req.getParameter(param_Name1); if (!isEmpty(parameter)){ args[j] = (Integer)Integer.parseInt(parameter); } break; default: for (String s:classNameList){ if (s.endsWith(simpleName)){simpleName = s; } } Class t = null; try { t = Class.forName(simpleName); } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("未找到参数实体类"); } Object o = null; try { o = t.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); System.out.println("实体类实例化失败"); } Field[] declaredFields = t.getDeclaredFields(); for (Field field : declaredFields){ String filed_name = field.getName(); Class fieldType = field.getType(); field.setAccessible(true); if(fieldType == String.class){if (!isEmpty(req.getParameter(filed_name))){ try { field.set(o,req.getParameter(filed_name)); } catch (IllegalAccessException e) { e.printStackTrace(); System.out.println("实体类参数注入失败"); }} }else if (fieldType == Integer.class){if (!isEmpty(req.getParameter(filed_name))){ try { String parameter1 = req.getParameter(filed_name); Integer i = Integer.parseInt(parameter1); field.set(o,i); } catch (IllegalAccessException e) { e.printStackTrace(); System.out.println("实体类参数注入失败"); }} } } args[j] = o; } } return args; } private RequestParam getRequestParamAnnotationByIndex(Annotation[][] parameterAnnotations,int j) { for (Annotation annotation :parameterAnnotations[j]){ Class type = annotation.annotationType(); if ("RequestParam".equals(type.getSimpleName())){ return (RequestParam) annotation; } } return null; } //获取参数注解上索引对应参数的RequestMapping注解 private void initWired() { SpringMvcBeanFactory beanFactory = (SpringMvcBeanFactory) SpringMvcBeanFactory.getBeanFactory(); Set set = beanFactory.keySet(); for (String key:set){ Object bean = beanFactory.getBean(key); Field[] fields = bean.getClass().getDeclaredFields(); if (fields.length>0){ for (Field field:fields){ if (field.isAnnotationPresent(AutoWired.class)){ String value = field.getAnnotation(AutoWired.class).value(); field.setAccessible(true); try {if (!"".equals(value)) { field.set(bean, beanFactory.getBean(value));}field.set(bean, beanFactory.getBean(field.getName())); } catch (IllegalAccessException e) {e.printStackTrace();System.out.println("bean注入失败"); } } } } } } private void initBeans() { //获取bean工厂 BeanFactory beanFactory = SpringMvcBeanFactory.getBeanFactory(); for (String className:classNameList){ Class bean = null; try { bean = Class.forName(className); } catch (ClassNotFoundException e) { System.out.println("没有找到类"); } if (bean.isAnnotationPresent(Controller.class)||bean.isAnnotationPresent(Service.class)){ Object o = null; try { o = bean.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); System.out.println("生成实例化对象失败"); } catch (IllegalAccessException e) { e.printStackTrace(); } beanFactory.setBean(o); } if (bean.isAnnotationPresent(Component.class)){ Component annotation = (Component) bean.getAnnotation(Component.class); Object o = null; try { o = bean.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } if ("".equals(annotation.value())){ beanFactory.setBean(o); }else { String name = annotation.value(); beanFactory.setBeanByName(name,o); } } } } private void initClassNameList() throws FileNotFoundException { //获取配置文件 URL resource = DispatcherServlet.class.getClassLoader().getResource("application.yaml"); Yaml yaml = new Yaml(); Map load = (Map) yaml.load(new FileInputStream(resource.getFile())); Map application = (Map) load.get("springmvc"); Map scanPackage_map = (Map) application.get("application"); String scanPackage = (String) scanPackage_map.get("scanPackage"); scanClassList(scanPackage); } private void scanClassList(String scanPackage) { URL url = DispatcherServlet.class.getClassLoader().getResource(scanPackage.replaceAll("\\.","/")); File file = new File(url.getFile()); File[] files = file.listFiles(); for (File file_path:files){ if (file_path.isDirectory()){ scanClassList(scanPackage+"."+file_path.getName()); }else if (file_path.getName().endsWith(".class")){ classNameList.add(scanPackage+"."+file_path.getName().replace(".class", "")); } } } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); String requestURI = req.getRequestURI(); HandlerMapping handlerMapping = handlerMappings.get(requestURI); if (handlerMapping==null){ resp.getWriter().write("404 NOT FOUND"); return; } Object instance = handlerMapping.getController(); Method method = handlerMapping.getMethod(); Object[] args = searchParam(method, req, resp); httpRequestHandler.invoke(instance,method,args,req,resp); } //判断字符串是否为空 public static boolean isEmpty(String s){ return (!"".equals(s)&&s!=null)?false:true; }}
BeanFactory bean工厂接口
package com.ji.spring.core.bean;public interface BeanFactory { void setBean(Object o); Object getBean(String beanName); void setBeanByName(String str,Object o);}
SpringMvcBeanFactory工厂类
package com.ji.spring.core.bean;import java.util.HashMap;public class SpringMvcBeanFactory extends HashMap implements BeanFactory{ //单例 private static BeanFactory springMvcBeanFactory; private void setSpringMvcBeanFactory(){}; public synchronized static BeanFactory getBeanFactory(){ if (springMvcBeanFactory == null){ springMvcBeanFactory = new SpringMvcBeanFactory(); } return springMvcBeanFactory; } @Override public void setBean(Object object) { String name = object.getClass().getSimpleName(); name = firstWordToLowerCase(name); this.put(name, object); } @Override public void setBeanByName(String name,Object object){ this.put(name, object); } @Override public Object getBean(String beanName) { return this.get(beanName); } //首字母小写 public static String firstWordToLowerCase(String str){ String str_ = str.substring(0,1).toLowerCase()+str.substring(1); return str_; }}
handler处理器接口
public interface Handler { void invoke(Object instance, Method method, Object[] args, HttpServletRequest req, HttpServletResponse resp) throws Exception;}
HttpRequestHandler处理器类
package com.ji.spring.springmvc.servlet;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class HttpRequestHandler implements Handler{ public void invoke(Object instance, Method method, Object[] args, HttpServletRequest req, HttpServletResponse resp) throws IOException { Object invoke = null; Class type = method.getReturnType(); try { invoke = method.invoke(instance, args); } catch (IllegalAccessException e) { e.printStackTrace(); System.out.println("方法未声明public"); } catch (InvocationTargetException e) { e.printStackTrace(); } if (invoke!=null){ ObjectMapper objectMapper = new ObjectMapper(); String s = objectMapper.writeValueAsString(invoke); resp.setHeader("Content-Type", "application/json;charset=UTF-8"); resp.setContentType("text/html;charset=UTF-8"); resp.getWriter().write(s); } }}
HandlerMapping处理器映射类
package com.ji.spring.springmvc.servlet;import java.lang.reflect.Method;public class HandlerMapping { private Object controller; private Method method; public HandlerMapping() { } public HandlerMapping(Object controller,Method method) { this.controller = controller; this.method = method; } public Method getMethod() { return method; } public void setMethod(Method method) { this.method = method; } public Object getController() { return controller; } public void setController(Object controller) { this.controller = controller; }}