1. 程式人生 > >手寫Spring框架學習筆記

手寫Spring框架學習筆記

public class DispatcherServlet extends HttpServlet {

    private Properties contextConfig = new Properties();

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

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

    private Map<String,Method> handlerMapping = new HashMap<>();

    @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 {
        //執行階段,根據使用者請求的URL進行自動分發和排程
        try {
            doDispatch(req,resp);
        } catch (Exception e) {
            e.printStackTrace();
            resp.getWriter().write("500 Detail:" + Arrays.toString(e.getStackTrace()));
        }
    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        if(this.handlerMapping.isEmpty()){
            return;
        }
        //絕對路徑
        String url  = req.getRequestURI();
        //處理成相對路徑
        String contextPath = req.getContextPath();
        url = url.replace(contextPath, "").replaceAll("/+", "/");
        if(!this.handlerMapping.containsKey(url)){
            resp.getWriter().write("404 Not found");
            return;
        }

        Method method = this.handlerMapping.get(url);
        //如何拿到例項?
        //唯一的方式從IOC容器中拿
        //繼續投機取巧
        String beanName =  lowerFirstCase(method.getDeclaringClass().getSimpleName());
        System.out.println("beanName:" + beanName);
        Map<String,String[]> params = req.getParameterMap();

        method.invoke(ioc.get(beanName), new Object[]{req, resp,params.get("name")[0]});


       // System.out.println(method);
    }


    @Override
    public void init(ServletConfig config) throws ServletException {
        //1、載入配置檔案
        doLoadConfig(config.getInitParameter("contextConfigLocation"));

        //2. 掃描所有相關的類
        doScanner(contextConfig.getProperty("scanPackage"));

        //3.初始化剛剛掃描到所有相關的類,並且把它儲存在IOC容器中
        doInstance();

        //4. 實現依賴注入 DI 自動賦值
        doAutowired();

        //5. 初始化handlerMapping
        initHandleMapping();

        System.out.println("Spring is init");
    }

    private void initHandleMapping() {
        if(ioc.isEmpty()){
            return;
        }

        for(Map.Entry<String, Object> entry: ioc.entrySet()) {
            Class<?> clazz = entry.getValue().getClass();
            if(!clazz.isAnnotationPresent(Controller.class)){
                continue;
            }

            String baseUrl = "";
            if(clazz.isAnnotationPresent(RequestMapping.class)){
                RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
                baseUrl =  requestMapping.value();
            }

            Method[] methods = clazz.getMethods(); //只認public的方法
            for(Method method : methods){
                if(!method.isAnnotationPresent(RequestMapping.class)){
                    continue;
                }
                RequestMapping requestMapping =  method.getAnnotation(RequestMapping.class);
               String url = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+", "/");
                handlerMapping.put(url,method);
                System.out.println("Mapped:" + url +"," + method);
            }

            Field[] fields = entry.getValue().getClass().getDeclaredFields();
            for (Field field : fields) {
                if (!field.isAnnotationPresent(Autowired.class)) {
                    continue;
                }
            }
        }
    }

    private void doAutowired() {
        if(ioc.isEmpty()){
            return;
        }

        for(Map.Entry<String, Object> entry: ioc.entrySet()){
           Field[] fields = entry.getValue().getClass().getDeclaredFields();
           for(Field field: fields){
               if(!field.isAnnotationPresent(Autowired.class)){
                   continue;
               }

              Autowired autowired =  field.getAnnotation(Autowired.class);
              String beanName = autowired.value().trim();
              if("".equals(beanName)){
                  beanName = field.getType().getName();
              }

              field.setAccessible(true); //強制暴力訪問
               try {
                   field.set(entry.getValue(), ioc.get(beanName));
               } catch (IllegalAccessException e) {
                   e.printStackTrace();
                   continue;
               }

           }
        }
    }

    private void doInstance() {
        if(classNames.isEmpty()){
            return;
        }

        try{
            for (String className: classNames) {
               Class<?> clazz =  Class.forName(className);
               //例項化,把例項化的物件儲存到IOC容器之中

                if(clazz.isAnnotationPresent(Controller.class)){
                    Object instance = clazz.newInstance();
                    String beanName = lowerFirstCase(clazz.getSimpleName());
                    ioc.put(beanName, instance);
                } else if(clazz.isAnnotationPresent(Service.class)){
                    //因為Service有可能注入的不是它本身,有可能是它的實現類
                    //1、預設類名首字母小寫

                    //2、自定義的beanName
                    Service service = clazz.getAnnotation(Service.class);
                    String beanName = service.value();
                    if("".equals(beanName)){
                         beanName = lowerFirstCase(clazz.getSimpleName());
                    }
                    Object instance = clazz.newInstance();
                    ioc.put(beanName, instance);

                    //3、如果是介面,投機取巧的方式,用它的介面型別作為key
                    Class<?>[] interfaces = clazz.getInterfaces();
                    for(Class<?> i : interfaces){
                        if(ioc.containsKey(i.getName())){
                            throw  new Exception("The beanName is exists");
                        }
                        ioc.put(i.getName(), instance);
                    }

                }else{
                    continue;
                }

            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    /**
     * 類名首字母小寫
     */
    private String lowerFirstCase(String simpleName) {
        char[] chars = simpleName.toCharArray();
        chars[0] += 32;
        return  String.valueOf(chars);
    }

    private void doScanner(String scanPackage) {
        URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
        File classDir = new File(url.getFile());
        for(File file : classDir.listFiles()){
            if(file.isDirectory()){
                doScanner(scanPackage + "." + file.getName());
            }else{
                if(file.getName().endsWith(".class")){
                    String classname = (scanPackage + "." +file.getName()).replace(".class","");
                    classNames.add(classname);
                }
            }
        }
    }

    private void doLoadConfig(String contextConfigLocation) {
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
        try {
            contextConfig.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

相關推薦

Spring框架學習筆記

public class DispatcherServlet extends HttpServlet { private Properties contextConfig = new Properties(); private List<String> classN

spring框架學習筆記4:SpringAOP實現原理

odin 就是 sets 使用 point 攔截 ceo oca ssl AOP AOP(Aspect Oriented Programming),即面向切面編程,可以說是OOP(Object Oriented Programming,面向對象編程)的補充和完善。OOP引入

Spring框架學習筆記(二)

約束 存在 基礎 核心 但是 註解 文件的 分享 strong 上接Spring框架學習筆記(一) IOC和DI區別 (1)IOC: 控制反轉,把對象創建交給spring進行配置 (2)DI: 依賴註入,向類裏面的屬性中設置值 (3)關系:依賴註入不能單獨存在,需要在i

Spring框架學習筆記(四)

兩個 低版本 事務管理器 對象關系 多行 通配符 表單 spring整合 val 上接Spring框架學習筆記(三) 聲明式事務管理(xml配置) 1 配置文件方式使用aop思想配置 第一步 配置事務管理器 第二步 配置事務增強 第三步 配置切面 聲明式事務

Spring框架學習筆記——IoC(Inversion of Control,控制反轉)和AOP(Aspect Oriented Programming,面向切面程式設計)

1、Spring IoC IoC是一個Bean容器,在Spring中,它認為一切Java資源都是Java Bean,容器的目標就是管理這些Bean和它們之間的關係。所以在Spring IoC裡面裝載的各種Bean,也可以理解為Java的各種資源,包括Java Bean的建立、事件、行為和Java

Java Spring框架學習筆記(持續更新)

IOC、DI IOC容器:控制反轉。通常例項化一個類的物件,我們都會用new關鍵字來例項化。而“控制反轉”將物件例項化的這一操作從程式設計師手動完成轉交給IOC容器完成。 DI(依賴注入Dependency injection):容器建立完物件後,處理物件與物件之間的依賴關係。 依賴

Spring框架學習筆記(三)-- Spring MVC

      所謂MVC,即模型-檢視-控制器,是一種比較普遍使用的設計模式。它通過分離模型、檢視、控制器在程式中的角色進行解耦的。通常,模型負責封裝應用程式資料在檢視層的展示,檢視負責展示這些資料,控制器負責接收來自使用者的請求,並呼叫後臺服務來處理業務邏輯。(核心思想是將業

Spring框架學習筆記(四)-- Mybatis

Mybatis是什麼MyBatis 本是apache的一個開源專案iBatis, 2010年這個專案由apache software foundation 遷移到了google code,並且改名為MyBatis,實質上Mybatis對ibatis進行一些改進。MyBatis

spring框架,實現簡單的ioc功能

 最近重新鞏固了基礎, 把spring框架重新學習了一遍。現在用自己的理解將spring框架寫一遍。這次先簡單實現,以後會慢慢拓展,暫時定的計劃是spirngmvc和mybatis的整合。整體思路是使用dom4j解析xml檔案,然後反射注入到Person類中。簡單明瞭,不做過

彷徨 | spring框架學習筆記

目錄 1.spring框架概念 1 spring是輕量級開源框架: Spring是一個開源框架,Spring是於2003 年興起的一個輕量級的Java 開發框架,由 Rod Johnson 在其著作 Expert One-On-O

Spring框架學習筆記(一)

     1: spring 層次的分析                 spring貫穿整個層次,管理各個層的bean,並維護bean之間的關係。     2 :spring 的快速入門                  傳統模式需要建立物件(new  Object()),

Spring框架學習筆記(1)——控制反轉IOC與依賴注入DI

Spring框架的主要作用,就是提供了一個容器,使用該容器就可以建立並管理物件。比如說Dao類等,又或者是具有多依賴關係的類(Student類中包含有Teacher類的成員變數) Spring有兩個核心概念,一個是控制反轉(IOC,全稱為Inverse of Control),另一個則是面向切面程式設計(AO

Spring框架學習筆記(2)——面向切面程式設計AOP

介紹 概念 面向切面程式設計AOP與面向物件程式設計OOP有所不同,AOP不是對OOP的替換,而是對OOP的一種補充,AOP增強了OOP。 假設我們有幾個業務程式碼,都呼叫了某個方法,按照OOP的思想,我們就會將此方法封裝在一個類中,之後通過物件.方法名呼叫 我們可以看作我們的業務程式碼被其他程式碼入侵或者是

Spring框架學習筆記(3)——SpringMVC框架

SpringMVC框架是基於Spring框架,可以讓我們更為方便的進行Web的開發,實現前後端分離 思路和原理 我們之前仿照SpringMVC定義了一個自定義MVC框架,兩者的思路其實都是一樣的。 建議結合兩篇文章進行學習 JSP學習筆記(6)—— 自定義MVC框架 首先,提供一個前置攔截器(Dispatch

Spring框架學習筆記(5)——Spring Boot建立與使用

Spring Boot可以更為方便地搭建一個Web系統,之後伺服器上部署也較為方便 建立Spring boot專案 1. 使用IDEA建立專案 2. 修改groupid和artifact 3. 一路next,自動IDEA就會自動下載依賴的jar包 4. 執行 之後執行專案(Application類

Spring框架學習筆記(6)——阿里雲伺服器部署Spring Boot專案(jar包)

最近接外包,需要部署伺服器,便是參考了網上的幾篇博文,成功在阿里雲伺服器成功部署了Spring Boot專案,特記下本篇筆記 Spring Boot專案打包 這裡說一下部署的一些問題 1.mysql驅動 建立spring boot的時候,在介面選擇添加了MySql的依賴,但是,實際專案測試的時候,發現驅動錯誤

Spring框架學習筆記(7)——Spring Boot 實現上傳和下載

最近忙著都沒時間寫部落格了,做了個專案,實現了下載功能,沒用到上傳,寫這篇文章也是順便參考學習瞭如何實現上傳,上傳和下載做一篇筆記吧 下載 主要有下面的兩種方式: 通過ResponseEntity實現 通過寫HttpServletResponse的OutputStream實現 我只測試了ResponseE

Spring框架學習筆記(8)——spring boot+mybatis plus+mysql專案環境搭建

之前寫的那篇Spring框架學習筆記(5)——Spring Boot建立與使用,發現有多小細節沒有提及,,正好現在又學習了mybatis plus這款框架,打算重新整理一遍,並將細節說清楚 1.通過IDEA建立spring boot 2.專案相關配置 只需要修改第一個和第二個,下面的其他選項會自動改變

Spring框架學習筆記(9)——API介面設計相關知識及具體編碼實現

最近需要設計一個API伺服器,想要把API介面搞得規範一下,就通過網上搜集到了一些資料,以下便是自己的一些理解以及相關的具體實現 本文采用的是spring boot+maven的方案 restful規範 這個規範我在這裡也不打算長篇大論地講解,怎麼說呢,有人喜歡有人討厭,我也不去爭,因為我經驗不多,看法和大佬

Tensorflow 實戰Google深度學習框架——學習筆記(六)LeNet-5網路實現MNIST數字集識別

使用LeNet-5模型實現MNIST手寫數字識別,其神經網路架構如下: 一、詳細介紹LeNet-5模型每一層的結構 第一層,卷積層 這一層輸入原始的影象畫素,接受的輸入層大小為32*32*1,第一個卷積層過濾器尺寸為5*5,共6個,不使用全0填