国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(八)--制作Starter

AprilJ / 1538人閱讀

摘要:服務(wù)器相關(guān)配置啟動(dòng)類資源目錄目錄靜態(tài)文件目錄端口號(hào)目錄目錄實(shí)現(xiàn)內(nèi)嵌服務(wù)器在上一章文章從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的框架七實(shí)現(xiàn)已經(jīng)在文件中引入了依賴,所以這里就不用引用了。

spring-boot的Starter

一個(gè)項(xiàng)目總是要有一個(gè)啟動(dòng)的地方,當(dāng)項(xiàng)目部署在tomcat中的時(shí)候,經(jīng)常就會(huì)用tomcat的startup.sh(startup.bat)的啟動(dòng)腳本來(lái)啟動(dòng)web項(xiàng)目

而在spring-boot的web項(xiàng)目中基本會(huì)有類似于這樣子的啟動(dòng)代碼:

@SpringBootApplication
public class SpringBootDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootDemoApplication.class, args);
    }
}

這個(gè)方法實(shí)際上會(huì)調(diào)用spring-boot的SpringApplication類的一個(gè)run方法:

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    try {
        // 1.加載環(huán)境變量、參數(shù)等
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                                                                 applicationArguments);
        configureIgnoreBeanInfo(environment);
        Banner printedBanner = printBanner(environment);
        // 2.加載Bean(IOC、AOP)等
        context = createApplicationContext();
        exceptionReporters = getSpringFactoriesInstances(
            SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
        prepareContext(context, environment, listeners, applicationArguments,
                       printedBanner);
        //會(huì)調(diào)用一個(gè)AbstractApplicationContext@refresh()方法,主要就是在這里加載Bean,方法的最后還會(huì)啟動(dòng)服務(wù)器
        refreshContext(context);
        afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                .logStarted(getApplicationLog(), stopWatch);
        }
        listeners.started(context);
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }

    try {
        listeners.running(context);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

這段代碼還是比較長(zhǎng)的,不過(guò)實(shí)際上主要就做了兩個(gè)事情:1.加載環(huán)境變量、參數(shù)等 2.加載Bean(IOC、AOP)等。3.如果獲得的ApplicationContextServletWebServerApplicationContext,那么在refresh()之后會(huì)啟動(dòng)服務(wù)器,默認(rèn)的就是tomcat服務(wù)器。

我覺得spring-boot啟動(dòng)器算是spring-boot中相對(duì)來(lái)說(shuō)代碼清晰易懂的,同時(shí)也非常容易了解到整個(gè)spring-boot的流程結(jié)構(gòu),建議大家能夠去看一下。

實(shí)現(xiàn)Starter

了解到spring-boot的啟動(dòng)器的作用和原理之后,我們可以開始實(shí)現(xiàn)doodle的啟動(dòng)器了。

根據(jù)剛才提到的,啟動(dòng)器要做以下幾件事

加載一些參數(shù)變量

加載Bean(IOC、AOP)等工作

啟動(dòng)服務(wù)器

Configuration保存變量

在com.zbw包下創(chuàng)建類Configuration用于保存一些全局變量,目前這個(gè)類只保存了現(xiàn)在實(shí)現(xiàn)的功能所需的變量。

package com.zbw;
import ...

/**
 * 服務(wù)器相關(guān)配置
 */
@Builder
@Getter
public class Configuration {

    /**
     * 啟動(dòng)類
     */
    private Class bootClass;

    /**
     * 資源目錄
     */
    @Builder.Default
    private String resourcePath = "src/main/resources/";

    /**
     * jsp目錄
     */
    @Builder.Default
    private String viewPath = "/templates/";

    /**
     * 靜態(tài)文件目錄
     */
    @Builder.Default
    private String assetPath = "/static/";

    /**
     * 端口號(hào)
     */
    @Builder.Default
    private int serverPort = 9090;

    /**
     * tomcat docBase目錄
     */
    @Builder.Default
    private String docBase = "";

    /**
     * tomcat contextPath目錄
     */
    @Builder.Default
    private String contextPath = "";
}
實(shí)現(xiàn)內(nèi)嵌Tomcat服務(wù)器

在上一章文章從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(七)--實(shí)現(xiàn)MVC已經(jīng)在pom.xml文件中引入了tomcat-embed依賴,所以這里就不用引用了。

先在com.zbw.mvc下創(chuàng)建一個(gè)包server,然后再server包下創(chuàng)建一個(gè)接口Server

package com.zbw.mvc.server;

/**
 * 服務(wù)器 interface
 */
public interface Server {
    /**
     * 啟動(dòng)服務(wù)器
     */
    void startServer() throws Exception;

    /**
     * 停止服務(wù)器
     */
    void stopServer() throws Exception;
}

因?yàn)榉?wù)器有很多種,雖然現(xiàn)在只用tomcat,但是為了方便擴(kuò)展和修改,就先創(chuàng)建一個(gè)通用的server接口,每個(gè)服務(wù)器都要實(shí)現(xiàn)這個(gè)接口。

接下來(lái)就創(chuàng)建TomcatServer類,這個(gè)類實(shí)現(xiàn)Server

package com.zbw.mvc.server;
import ...

/**
 * Tomcat 服務(wù)器
 */
@Slf4j
public class TomcatServer implements Server {

    private Tomcat tomcat;

    public TomcatServer() {
        new TomcatServer(Doodle.getConfiguration());
    }

    public TomcatServer(Configuration configuration) {
        try {
            this.tomcat = new Tomcat();
            tomcat.setBaseDir(configuration.getDocBase());
            tomcat.setPort(configuration.getServerPort());

            File root = getRootFolder();
            File webContentFolder = new File(root.getAbsolutePath(), configuration.getResourcePath());
            if (!webContentFolder.exists()) {
                webContentFolder = Files.createTempDirectory("default-doc-base").toFile();
            }

            log.info("Tomcat:configuring app with basedir: [{}]", webContentFolder.getAbsolutePath());
            StandardContext ctx = (StandardContext) tomcat.addWebapp(configuration.getContextPath(), webContentFolder.getAbsolutePath());
            ctx.setParentClassLoader(this.getClass().getClassLoader());

            WebResourceRoot resources = new StandardRoot(ctx);
            ctx.setResources(resources);
            // 添加jspServlet,defaultServlet和自己實(shí)現(xiàn)的dispatcherServlet
            tomcat.addServlet("", "jspServlet", new JspServlet()).setLoadOnStartup(3);
            tomcat.addServlet("", "defaultServlet", new DefaultServlet()).setLoadOnStartup(1);
            tomcat.addServlet("", "dispatcherServlet", new DispatcherServlet()).setLoadOnStartup(0);
            ctx.addServletMappingDecoded("/templates/" + "*", "jspServlet");
            ctx.addServletMappingDecoded("/static/" + "*", "defaultServlet");
            ctx.addServletMappingDecoded("/*", "dispatcherServlet");
            ctx.addServletMappingDecoded("/*", "dispatcherServlet");
        } catch (Exception e) {
            log.error("初始化Tomcat失敗", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public void startServer() throws Exception {
        tomcat.start();
        String address = tomcat.getServer().getAddress();
        int port = tomcat.getConnector().getPort();
        log.info("local address: http://{}:{}", address, port);
        tomcat.getServer().await();
    }

    @Override
    public void stopServer() throws Exception {
        tomcat.stop();
    }

    private File getRootFolder() {
        try {
            File root;
            String runningJarPath = this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath().replaceAll("", "/");
            int lastIndexOf = runningJarPath.lastIndexOf("/target/");
            if (lastIndexOf < 0) {
                root = new File("");
            } else {
                root = new File(runningJarPath.substring(0, lastIndexOf));
            }
            log.info("Tomcat:application resolved root folder: [{}]", root.getAbsolutePath());
            return root;
        } catch (URISyntaxException ex) {
            throw new RuntimeException(ex);
        }
    }
}

這個(gè)類主要就是配置tomcat,和配置普通的外部tomcat有點(diǎn)類似只是這里是用代碼的方式。注意的是在getRootFolder()方法中獲取的是當(dāng)前項(xiàng)目目錄下的target文件夾,即idea默認(rèn)的編譯文件保存的位置,如果修改了編譯文件保存位置,這里也要修改。

特別值得一提的是這部分代碼:

// 添加jspServlet,defaultServlet和自己實(shí)現(xiàn)的dispatcherServlet
tomcat.addServlet("", "jspServlet", new JspServlet()).setLoadOnStartup(3);
tomcat.addServlet("", "defaultServlet", new DefaultServlet()).setLoadOnStartup(1);
tomcat.addServlet("", "dispatcherServlet", new DispatcherServlet()).setLoadOnStartup(0);
ctx.addServletMappingDecoded("/templates/" + "*", "jspServlet");
ctx.addServletMappingDecoded("/static/" + "*", "defaultServlet");
ctx.addServletMappingDecoded("/*", "dispatcherServlet");
ctx.addServletMappingDecoded("/*", "dispatcherServlet");

這部分代碼就相當(dāng)于原來(lái)的web.xml配置的文件,而且defaultServletjspServlet這兩個(gè)servlet是tomcat內(nèi)置的servlet,前者用于處理靜態(tài)資源如css、js文件等,后者用于處理jsp。如果有安裝tomcat可以去tomcat目錄下的conf文件夾里有個(gè)web.xml文件,里面有幾行就是配置defaultServletjspServlet


    default
    org.apache.catalina.servlets.DefaultServlet
    
        debug
        0
    
    
        listings
        false
    
    1


    jsp
    org.apache.jasper.servlet.JspServlet
    
        fork
        false
    
    
        xpoweredBy
        false
    
    3

而dispatcherServlet就是從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(七)--實(shí)現(xiàn)MVC這一節(jié)中實(shí)現(xiàn)的分發(fā)器。這三個(gè)servlet都設(shè)置了LoadOnStartup,當(dāng)這個(gè)值大于等于0時(shí)就會(huì)隨tomcat啟動(dòng)也實(shí)例化。

實(shí)現(xiàn)啟動(dòng)器類

在com.zbw包下創(chuàng)建一個(gè)類作為啟動(dòng)器類,就是類似于SpringApplication這樣的。這里起名叫做Doodle,因?yàn)檫@個(gè)框架就叫doodle嘛。

package com.zbw;
import ...

/**
 * Doodle Starter
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Slf4j
public final class Doodle {

    /**
     * 全局配置
     */
    @Getter
    private static Configuration configuration = Configuration.builder().build();

    /**
     * 默認(rèn)服務(wù)器
     */
    @Getter
    private static Server server;

    /**
     * 啟動(dòng)
     */
    public static void run(Class bootClass) {
        run(Configuration.builder().bootClass(bootClass).build());
    }

    /**
     * 啟動(dòng)
     */
    public static void run(Class bootClass, int port) {
        run(Configuration.builder().bootClass(bootClass).serverPort(port).build());
    }

    /**
     * 啟動(dòng)
     */
    public static void run(Configuration configuration) {
        new Doodle().start(configuration);
    }

    /**
     * 初始化
     */
    private void start(Configuration configuration) {
        try {
            Doodle.configuration = configuration;
            String basePackage = configuration.getBootClass().getPackage().getName();
            BeanContainer.getInstance().loadBeans(basePackage);
           //注意Aop必須在Ioc之前執(zhí)行
            new Aop().doAop();
            new Ioc().doIoc();

            server = new TomcatServer(configuration);
            server.startServer();
        } catch (Exception e) {
            log.error("Doodle 啟動(dòng)失敗", e);
        }
    }
}

這個(gè)類中有三個(gè)啟動(dòng)方法都會(huì)調(diào)用Doodle@start()方法,在這個(gè)方法里做了三件事:

讀取configuration中的配置

BeanContainer掃描包并加載Bean

執(zhí)行Aop

執(zhí)行Ioc

啟動(dòng)Tomcat服務(wù)器

這里的執(zhí)行是有順序要求的,特別是Aop必須要在Ioc之前執(zhí)行,不然注入到類中的屬性都是沒被代理的。

修改硬編碼

在之前寫mvc的時(shí)候有一處有個(gè)硬編碼,現(xiàn)在有了啟動(dòng)器和全局配置,可以把之前的硬編碼修改了

對(duì)在com.zbw.mvc包下的ResultRender類里的resultResolver()方法,當(dāng)判斷為跳轉(zhuǎn)到j(luò)sp文件的時(shí)候跳轉(zhuǎn)路徑那一行代碼修改:

try {
    Doodle.getConfiguration().getResourcePath();
    // req.getRequestDispatcher("/templates/" + path).forward(req, resp);
    req.getRequestDispatcher(Doodle.getConfiguration().getResourcePath() + path).forward(req, resp);
} catch (Exception e) {
    log.error("轉(zhuǎn)發(fā)請(qǐng)求失敗", e);
    // TODO: 異常統(tǒng)一處理,400等...
}
啟動(dòng)和測(cè)試項(xiàng)目

現(xiàn)在doodle框架已經(jīng)完成其功能了,我們可以簡(jiǎn)單的創(chuàng)建一個(gè)Controller來(lái)感受一下這個(gè)框架。

在com包下創(chuàng)建sample包,然后在com.sample包下創(chuàng)建啟動(dòng)類APP

package com.sample;

import com.zbw.Doodle;
public class App {
    public static void main(String[] args) {
        Doodle.run(App.class);
    }
}

然后再創(chuàng)建一個(gè)ControllerDoodleController:

package com.sample;
import com.zbw.core.annotation.Controller;
import com.zbw.mvc.annotation.RequestMapping;
import com.zbw.mvc.annotation.ResponseBody;

@Controller
@RequestMapping
public class DoodleController {
    @RequestMapping
    @ResponseBody
    public String hello() {
        return "hello doodle";
    }
}

接著再運(yùn)行App的main方法,就能啟動(dòng)服務(wù)了。

從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(一)--前言

從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(二)--實(shí)現(xiàn)Bean容器

從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(三)--實(shí)現(xiàn)IOC

從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(四)--實(shí)現(xiàn)AOP

從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(五)--引入aspectj實(shí)現(xiàn)AOP切點(diǎn)

從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(六)--加強(qiáng)AOP功能

從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(七)--實(shí)現(xiàn)MVC

從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(八)--制作Starter

從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(九)--優(yōu)化MVC代碼

源碼地址:doodle

原文地址:從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(八)--制作Starter

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/76627.html

相關(guān)文章

  • 從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易Java MVC框架

    摘要:不過(guò)仔細(xì)了解了一段時(shí)候發(fā)現(xiàn),其實(shí)他的原理是很簡(jiǎn)單的,所以想要自己也動(dòng)手實(shí)現(xiàn)一個(gè)功能類似的框架。原文地址從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的框架 前言 最近在看spring-boot框架的源碼,看了源碼之后更是讓我感受到了spring-boot功能的強(qiáng)大。而且使用了很多的設(shè)計(jì)模式,讓人在看的時(shí)候覺得有點(diǎn)難以下手。 不過(guò)仔細(xì)了解了一段時(shí)候發(fā)現(xiàn),其實(shí)他的原理是很簡(jiǎn)單的,所以想要自己也動(dòng)手實(shí)現(xiàn)一個(gè)功能類似的...

    neuSnail 評(píng)論0 收藏0
  • 從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易Java MVC框架(五)--引入aspectj實(shí)現(xiàn)AOP切點(diǎn)

    摘要:接下來(lái)就可以把這個(gè)切點(diǎn)類加入到我們之前實(shí)現(xiàn)的功能中了。實(shí)現(xiàn)的切點(diǎn)功能首先改裝注解,把之前改成來(lái)存儲(chǔ)表達(dá)式。測(cè)試用例在上一篇文章從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的框架四實(shí)現(xiàn)中的測(cè)試用例的基礎(chǔ)上修改測(cè)試用例。 前言 在上一節(jié)從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(四)--實(shí)現(xiàn)AOP中我們實(shí)現(xiàn)了AOP的功能,已經(jīng)可以生成對(duì)應(yīng)的代理類了,但是對(duì)于代理對(duì)象的選擇只能通過(guò)指定的類,這樣確實(shí)不方便也不合理。...

    wupengyu 評(píng)論0 收藏0
  • 從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易Java MVC框架(六)--加強(qiáng)AOP功能

    摘要:在前面的文章中實(shí)現(xiàn)的功能時(shí),目標(biāo)類都只能被一個(gè)切面代理,如果想要生成第二個(gè)代理類,就會(huì)把之前的代理類覆蓋。改裝原有功能現(xiàn)在要改裝原來(lái)的的實(shí)現(xiàn)代碼,讓的功能加入到框架中為了讓切面能夠排序,先添加一個(gè)注解,用于標(biāo)記排序。 前言 在前面從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(四)--實(shí)現(xiàn)AOP和從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(五)--引入aspectj實(shí)現(xiàn)AOP切點(diǎn)這兩節(jié)文章...

    Loong_T 評(píng)論0 收藏0
  • 從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易Java MVC框架(九)--優(yōu)化MVC代碼

    摘要:前言在從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的框架七實(shí)現(xiàn)中實(shí)現(xiàn)了框架的的功能,不過(guò)最后指出代碼的邏輯不是很好,在這一章節(jié)就將這一部分代碼進(jìn)行優(yōu)化。 前言 在從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易的Java MVC框架(七)--實(shí)現(xiàn)MVC中實(shí)現(xiàn)了doodle框架的MVC的功能,不過(guò)最后指出代碼的邏輯不是很好,在這一章節(jié)就將這一部分代碼進(jìn)行優(yōu)化。 優(yōu)化的目標(biāo)是1.去除DispatcherServlet請(qǐng)求分發(fā)器中的http邏...

    ruicbAndroid 評(píng)論0 收藏0
  • 從零開始實(shí)現(xiàn)一個(gè)簡(jiǎn)易Java MVC框架(二)--實(shí)現(xiàn)Bean容器

    摘要:容器實(shí)際上就是存放所有的地方,即以及相關(guān)信息對(duì)應(yīng)其實(shí)體的容器,為什么稱之為呢,因?yàn)樵谥?,定義信息和實(shí)例的東西叫。了解到這個(gè)以后接下來(lái)就可以開始編寫容器了,在包下創(chuàng)建一個(gè)類叫。獲取容器實(shí)例至此,這個(gè)容器就完成了。 項(xiàng)目準(zhǔn)備 首先確保你擁有以下環(huán)境或者工具 idea java 8 maven 3.3.X lombok插件 然后我們創(chuàng)建一個(gè)maven工程,編寫pom.xml引入一些需要的...

    paulquei 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<