手写springmvc框架ioc容器(简易版),实现实体类参数接收,并实现基于yaml配置文件

项目github地址:https://github.com/kongGe55/spring-mvc-test

整个项目只依赖了javaweb相关jar包

<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>servlet-api</artifactId>
      <version>6.0.29</version>
      <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.yaml/snakeyaml -->
    <dependency>
      <groupId>org.yaml</groupId>
      <artifactId>snakeyaml</artifactId>
      <version>1.17</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.8</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.8</version>
    </dependency>
  </dependencies>

不完善的地方

  1. 实体类参数接受只支持String类型和Interger,后期可以加上其他参数类型接收,支持类型有限;
  2. 只支持注解
  3. 还很多不完善的地方望指正,我也是在学习反射的使用

使用方法和springmvc一样,只不过配置文件要在resource下,名称application.yaml

在这里插入图片描述
配置web.xml

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>DispacherServlet</servlet-name>
    <servlet-class>com.ji.spring.springmvc.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>DispacherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

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;
	}
	@Override
	public 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<User> findUser(HttpServletResponse response) throws IOException {
        List<User> list = userService.findUser();
        return list;
    }
}

这里返回数据自动进行了处理
Service

@Component("userService") //也可以直接用@Service注解
public class UserService {
    public List<User> 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<User> 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<String> classNameList = new ArrayList<String>();
    private Map<String,HandlerMapping> 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<String> 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<? extends Annotation> type = annotation.annotationType();
            if ("RequestParam".equals(type.getSimpleName())){
                return (RequestParam) annotation;
            }
        }
        return null;
    }
    //获取参数注解上索引对应参数的RequestMapping注解


    private void initWired() {
        SpringMvcBeanFactory beanFactory = (SpringMvcBeanFactory) SpringMvcBeanFactory.getBeanFactory();
        Set<String> 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;
    }

}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值