天天看點

手寫spring核心第一版

第一版沒有使用設計模式,沒有封裝架構,隻是簡單的實作了IOC容器跟,DispatcherServlet處理請求

基本注解

/**
 * @author success
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    String value() default "";
}
---------------------------------------------
/**
 * @author lxz
 * @version 1.0
 * @className Controller
 * @description TODO
 * @Date 2019/9/3 10:18
 **/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {
    String value() default "";
}
---------------------------------------------
/**
 * @author lxz
 * @version 1.0
 * @className RequestMapping
 * @description TODO
 * @Date 2019/9/3 10:18
 **/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
    String value() default "";
}
---------------------------------------------
/**
 * @author lxz
 * @version 1.0
 * @className RequestParam
 * @description TODO
 * @Date 2019/9/3 10:18
 **/
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
    String value() default "";
}
---------------------------------------------
/**
 * @author lxz
 * @version 1.0
 * @className Service
 * @description TODO
 * @Date 2019/9/3 10:18
 **/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {
    String value() default "";
}
           

測試代碼

Action(controller)

/**
 * @author lxz
 * @version 1.0
 * @className DemoAction
 * @description TODO
 * @Date 2019/9/3 10:42
 **/
@Controller
@RequestMapping("/demo")
public class DemoAction {
    @Autowired
    private DemoService demoService;

    @RequestMapping("/query")
    public void query(HttpServletRequest req, HttpServletResponse res, @RequestParam("name") String name) {
        String result = demoService.get(name);
        try {
            res.getWriter().write(result);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
           

service

public interface DemoService {
    public String get(String name);
}
---------------------------------------------
/**
 * @author lxz
 * @version 1.0
 * @className DemoServiceImpl
 * @description TODO
 * @Date 2019/9/3 10:40
 **/
@Service
public class DemoServiceImpl implements DemoService {

    @Override
    public String get(String name) {
        return "my  name  is :" +name;
    }
}
           

web.xml配置

<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <servlet>
        <servlet-name>gpmvc</servlet-name>
        <servlet-class>com.apusic.mvcframework.v1.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:application.properties</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>gpmvc</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

           

application.properties

scanPackage=com.apusic.demo
           

核心類DispatcherServlet,繼承了HttpServlet,重寫了init,doGet,doPost方法.

流程init()初始化時,會掃描注解,把bean添加到IOC容器

處理請求的時候調用核心方法doDispath()處理

/**
 * @author lxz
 * @version 1.0
 * @className DispatcherServlet
 * @description TODO
 * @Date 2019/9/3 10:05
 **/
public class DispatcherServlet extends HttpServlet {
    private Map<String, Object> mapping = new HashMap<String, Object>();

    @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 {
        try {
            this.doDispatch(req, resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        String url = req.getRequestURI();
        String contextPath = req.getContextPath();
        url = url.replace(contextPath, "").replaceAll("/+", "/");
        if (!this.mapping.containsKey(url)) {
            resp.getWriter().write("404 Not Found");
            return;
        }
        Method method = (Method) this.mapping.get(url);
        Map<String, String[]> parameterMap = req.getParameterMap();
        String name = method.getDeclaringClass().getName();
        method.invoke(this.mapping.get(method.getDeclaringClass().getName()), new Object[]{req, resp, parameterMap.get(
                "name")[0]});
    }

    @Override
    public void init() throws ServletException {

        try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("application.properties")) {
            Properties ps = new Properties();
            ps.load(is);
            String scanPackage = ps.getProperty("scanPackage");
            doScanner(scanPackage);
            for (String className : mapping.keySet()) {
                if (!className.contains(".")) {
                    continue;
                }
                Class<?> clazz = Class.forName(className);
                if (clazz.isAnnotationPresent(Controller.class)) {
                    mapping.put(className, clazz.newInstance());
                    String baseUrl = "";
                    if (clazz.isAnnotationPresent(RequestMapping.class)) {
                        RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
                        baseUrl = requestMapping.value();
                    }
                    Method[] methods = clazz.getMethods();
                    for (Method method : methods) {
                        if (!method.isAnnotationPresent(RequestMapping.class)) {
                            continue;
                        }
                        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                        String url = baseUrl + requestMapping.value().replace("/+", "/");
                        mapping.put(url, method);
                        System.out.println("Mapped" + url + "," + method);
                    }
                } else if (clazz.isAnnotationPresent(Service.class)) {
                    Service service = clazz.getAnnotation(Service.class);
                    String beanName = service.value();
                    if ("".equals(beanName)) {
                        beanName = clazz.getName();
                    }
                    Object instance = clazz.newInstance();
                    mapping.put(beanName, instance);
                    for (Class<?> anInterface : clazz.getInterfaces()) {
                        mapping.put(anInterface.getName(), instance);
                    }
                } else {
                    continue;
                }
            }

            for (Object object : mapping.values()) {
                if (object == null) {
                    continue;
                }
                Class<?> clazz = object.getClass();
                if (clazz.isAnnotationPresent(Controller.class)) {
                    Field[] fields = clazz.getDeclaredFields();
                    for (Field field : fields) {
                        if (!field.isAnnotationPresent(Autowired.class)) {
                            continue;
                        }
                        String beanName = field.getAnnotation(Autowired.class).value();
                        if ("".equals(beanName)) {
                            beanName = field.getType().getName();
                            field.setAccessible(true);
                            field.set(mapping.get(clazz.getName()), mapping.get(beanName));
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("mvc framework  is init");
        }

    }

    private void doScanner(String scanPackage) {
        URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
        if (url != null) {
            File file = new File(url.getFile());

            for (File listFile : Objects.requireNonNull(file.listFiles())) {
                if (listFile.isDirectory()) {
                    doScanner(scanPackage + "." + listFile.getName());
                } else {
                    if (file.getName().endsWith(".class")) {
                        continue;
                    }
                    String className = (scanPackage + "." + listFile.getName().replace(".class", ""));
                    mapping.put(className, null);
                }
            }
        }
    }
}
           
手寫spring核心第一版

此時spring核心原理已經寫出來了.

後續更新優化版本