最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot超詳細(xì)深入講解底層原理

 更新時(shí)間:2022年07月19日 16:37:35   作者:惡魔的復(fù)活  
我們知道springboot內(nèi)部是通過spring框架內(nèi)嵌Tomcat實(shí)現(xiàn)的,當(dāng)然也可以內(nèi)嵌jetty,undertow等等web框架;另外springboot還有一個(gè)特別重要的功能就是自動(dòng)裝配,這又是如何實(shí)現(xiàn)的呢

手寫springboot

在日常開發(fā)中只需要引入下面的依賴就可以開發(fā)Servlet進(jìn)行訪問了。

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

那這是怎么做到的呢?今天就來一探究竟

首先新建一個(gè)maven項(xiàng)目rick-spring-boot,并創(chuàng)建兩個(gè)子項(xiàng)目分別是spring-boot和user,其中spring-boot項(xiàng)目就是模擬手寫一個(gè)簡單springboot,user就是用來測試手寫的spring-boot的。

user項(xiàng)目-測試工程

user項(xiàng)目包含pom.xml、UserController和UserService

<dependencies>
    <dependency>
      <groupId>com.rick.spring.boot</groupId>
      <artifactId>spring-boot</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>
@RestController
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("/user")
    public String getUser() {
        return userService.getUser();
    }
}
@Service
public class UserService {
    public String getUser() {
        return "rick";
    }
}

以及user項(xiàng)目的啟動(dòng)類RickApplication,而RickSpringApplication.run()是需要手寫的啟動(dòng)類以及@RickSpringBootApplication注解,都是需要在spring-boot項(xiàng)目實(shí)現(xiàn)。

import com.rick.spring.boot.RickSpringApplication;
import com.rick.spring.boot.RickSpringBootApplication;
@RickSpringBootApplication
public class RickApplication {
    public static void main(String[] args) {
        RickSpringApplication.run(RickApplication.class);
    }
}

Springboot項(xiàng)目

首先來看RickSpringApplication.run(RickApplication.class)方法需要做的事情:

(1)創(chuàng)建spring容器,并將傳入的class注冊(cè)到spring容器中

(2)啟動(dòng)web服務(wù),如tomcat,用來處理請(qǐng)求,并通過DispatchServlet將請(qǐng)求分發(fā)到Servlet進(jìn)行處理。

public class RickSpringApplication {
    public static void run(Class clz) {
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(clz);
        context.refresh();
        start(context);
    }
    public static void start(WebApplicationContext applicationContext) {
        System.out.println("start tomcat");
        Tomcat tomcat = new Tomcat();
        Server server = tomcat.getServer();
        Service service = server.findService("Tomcat");
        Connector connector = new Connector();
        connector.setPort(8081);
        Engine engine = new StandardEngine();
        engine.setDefaultHost("localhost");
        Host host = new StandardHost();
        host.setName("localhost");
        String contextPath = "";
        Context context = new StandardContext();
        context.setPath(contextPath);
        context.addLifecycleListener(new Tomcat.FixContextListener());
        host.addChild(context);
        engine.addChild(host);
        service.setContainer(engine);
        service.addConnector(connector);
        tomcat.addServlet(contextPath, "dispatcher", new DispatcherServlet(applicationContext));
        context.addServletMappingDecoded("/*", "dispatcher");
        try {
            tomcat.start();
        } catch (LifecycleException e) {
            e.printStackTrace();
        }
    }
}

RickApplication是被@RickSpringBootApplication注解修飾的,從如下代碼可以看出RickApplication是配置類,在被注冊(cè)到spring容器后,spring就會(huì)解析這個(gè)類。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Configuration
@ComponentScan
public @interface RickSpringBootApplication {
}

啟動(dòng)user項(xiàng)目RickApplication的main方法,

訪問UserController

至此一個(gè)簡單的spring-boot項(xiàng)目就整合完成了。

自動(dòng)配置

實(shí)現(xiàn)tomcat和jetty的切換

在使用springboot時(shí),如果我們不想使用tomcat作為請(qǐng)求處理服務(wù),而是jetty或者其他的web服務(wù),通常只需要將相關(guān)的tomcat依賴進(jìn)行排除,然后引入jetty的依賴就可以了,這就是springboot的自動(dòng)裝配的機(jī)制。接下來看看是如何實(shí)現(xiàn)的

定義一個(gè)WebServer接口和兩個(gè)實(shí)現(xiàn)類(tomcat和jetty),并寫好啟動(dòng)tomcat和jetty服務(wù)的代碼

public interface WebServer {
    void start();
}
public class JettyServer implements WebServer{
    @Override
    public void start() {
        System.out.println("start jetty");
    }
}
public class TomcatServer implements WebServer, ApplicationContextAware {
    private WebApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = (WebApplicationContext) applicationContext;
    }
    @Override
    public void start() {
        System.out.println("start tomcat");
        ...
        tomcat.addServlet(contextPath, "dispatcher", new DispatcherServlet(applicationContext));
        context.addServletMappingDecoded("/*", "dispatcher");
        try {
            tomcat.start();
        } catch (LifecycleException e) {
            e.printStackTrace();
        }
    }
}

定義AutoConfiguration接口,用來標(biāo)識(shí)需要自動(dòng)裝配的類。再定義一個(gè)WebServerAutoConfiguration類,它被表示為spring的一個(gè)配置類,最終我們需要導(dǎo)入這個(gè)類由spring來解析它,隨后spring會(huì)解析@Bean注解的方法來加載Bean。注意這里下面兩個(gè)方法還定義了@RickConditionalOnClass注解來決定是否需要解析這個(gè)bean,如果滿足條件則進(jìn)行解析,即應(yīng)用內(nèi)存在Tomcat或者Server的Class,會(huì)解析對(duì)應(yīng)方法的Bean,

public interface AutoConfiguration {
}
@Configuration
public class WebServerAutoConfiguration implements AutoConfiguration {
    @Bean
    @RickConditionalOnClass("org.apache.catalina.startup.Tomcat")
    public TomcatServer tomcatServer() {
        return new TomcatServer();
    }
    @Bean
    @RickConditionalOnClass("org.eclipse.jetty.server.Server")
    public JettyServer jettyWebServer() {
        return new JettyServer();
    }
}

來看@RickConditionalOnClass注解:當(dāng)spring解析被@RickConditionalOnClass注解的方法時(shí),spring就知道它被@Conditional修飾,并會(huì)在解析時(shí)執(zhí)行RickOnClassConditional的match()方法,來判斷是否滿足加載bean的條件。match()會(huì)嘗試加載傳入的類路徑名,如果應(yīng)用內(nèi)引入相關(guān)的jar則會(huì)加載成功返回true,反之,返回false。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Conditional(RickOnClassConditional.class)
public @interface RickConditionalOnClass {
    String value();
}
public class RickOnClassConditional implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String, Object> annotation = metadata.getAnnotationAttributes(RickConditionalOnClass.class.getName());
        try {
            context.getClassLoader().loadClass((String) annotation.get("value"));
        } catch (ClassNotFoundException e) {
            return false;
        }
        return true;
    }
}

引入WebServerAutoConfiguration,最簡單粗暴的方式就是通過@Import(WebServerAutoConfiguration.class)導(dǎo)入該類。但是spring-boot不可能這么做,成千上百的自動(dòng)配置寫在代碼里肯定不好。spring通過SPI機(jī)制,在resources目錄下創(chuàng)建如下目錄和文件

定義一個(gè)類實(shí)現(xiàn)DeferredImportSelector接口,并實(shí)現(xiàn)selectImports(),通過JDK的ServiceLoader加載以上文件中的類。通過@Import(WebServerImportSelector.class)注解導(dǎo)入該類spring在解析配置類的時(shí)候就會(huì)執(zhí)行selectImports(),從而將WebServerAutoConfiguration導(dǎo)入到spring容器中,spring就會(huì)解析這個(gè)配置類。

public class WebServerImportSelector implements DeferredImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        ServiceLoader<AutoConfiguration> load = ServiceLoader.load(AutoConfiguration.class);
        List<String> list = new ArrayList<>();
        for (AutoConfiguration loader : load) {
            list.add(loader.getClass().getName());
        }
        return list.toArray(new String[list.size()]);
    }
}

至此,springboot就做到了只需要修改user工程的maven依賴就能切換tomcat和jetty服務(wù)了

<dependency>
      <groupId>com.rick.spring.boot</groupId>
      <artifactId>spring-boot</artifactId>
      <version>1.0-SNAPSHOT</version>
      <exclusions>
        <exclusion>
          <groupId>org.apache.tomcat.embed</groupId>
          <artifactId>tomcat-embed-core</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-server</artifactId>
      <version>9.4.43.v20210629</version>
    </dependency>

重啟user項(xiàng)目

小結(jié)

通過手寫模擬springboot,加深對(duì)springboot底層原理的理解,對(duì)于開發(fā)和使用更加得心應(yīng)手。springboot本章小結(jié):

1、springboot主要是整合spring框架和內(nèi)嵌web服務(wù)器的框架

2、springboot通過條件注解、實(shí)現(xiàn)spring DeferredImportSelector接口和JDK自帶的SPI機(jī)制實(shí)現(xiàn)了自動(dòng)裝配的功能

到此這篇關(guān)于SpringBoot超詳細(xì)深入講解底層原理的文章就介紹到這了,更多相關(guān)SpringBoot底層原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot+SseEmitter和Vue3+EventSource實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送

    SpringBoot+SseEmitter和Vue3+EventSource實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送

    本文主要介紹了SpringBoot+SseEmitter和Vue3+EventSource實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-03-03
  • Spring框架依賴注入方法示例

    Spring框架依賴注入方法示例

    這篇文章主要介紹了Spring框架依賴注入方法示例,分享了三種方法示例,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • 詳解Java數(shù)組的一維和二維講解和內(nèi)存顯示圖

    詳解Java數(shù)組的一維和二維講解和內(nèi)存顯示圖

    這篇文章主要介紹了Java數(shù)組的一維和二維講解和內(nèi)存顯示圖,數(shù)組就相當(dāng)于一個(gè)容器,存放相同類型數(shù)據(jù)的容器。而數(shù)組的本質(zhì)上就是讓我們能 "批量" 創(chuàng)建相同類型的變量,需要的朋友可以參考下
    2023-05-05
  • java實(shí)現(xiàn)撲克牌發(fā)牌器

    java實(shí)現(xiàn)撲克牌發(fā)牌器

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)撲克牌發(fā)牌器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • 一文帶你了解SpringBoot的停機(jī)方式

    一文帶你了解SpringBoot的停機(jī)方式

    停機(jī)簡單的說,就是向應(yīng)用進(jìn)程發(fā)出停止指令之后,能保證正在執(zhí)行的業(yè)務(wù)操作不受影響,直到操作運(yùn)行完畢之后再停止服務(wù)。本文就來和大家聊聊Springboot的停機(jī)方式與停機(jī)處理
    2023-02-02
  • SpringBoot如何使用applicationContext.xml配置文件

    SpringBoot如何使用applicationContext.xml配置文件

    這篇文章主要介紹了SpringBoot使用applicationContext.xml配置文件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • JVM完全解讀之YGC來龍去脈分析

    JVM完全解讀之YGC來龍去脈分析

    YGC是JVM?GC當(dāng)前最為頻繁的一種GC,一個(gè)高并發(fā)的服務(wù)在運(yùn)行期間,會(huì)進(jìn)行大量的YGC,發(fā)生YGC時(shí),會(huì)進(jìn)行STW,一般時(shí)間都很短,除非碰到Y(jié)GC時(shí),存在大量的存活對(duì)象需要進(jìn)行拷貝
    2022-01-01
  • SpringMVC 上傳文件 MultipartFile 轉(zhuǎn)為 File的方法

    SpringMVC 上傳文件 MultipartFile 轉(zhuǎn)為 File的方法

    這篇文章主要介紹了SpringMVC 上傳文件 MultipartFile 轉(zhuǎn)為 File的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • SpringBoot整合minio服務(wù)的示例代碼

    SpringBoot整合minio服務(wù)的示例代碼

    本文主要介紹了SpringBoot整合minio服務(wù)的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • SpringBoot數(shù)據(jù)層處理方案精講

    SpringBoot數(shù)據(jù)層處理方案精講

    這篇文章主要介紹了SpringBoot數(shù)據(jù)層技術(shù)的解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-10-10

最新評(píng)論

惠水县| 景德镇市| 西丰县| 福鼎市| 南投县| 平乡县| 鞍山市| 珲春市| 苍山县| 承德市| 株洲市| 揭阳市| 武义县| 天峻县| 微山县| 边坝县| 荥阳市| 察隅县| 苗栗县| 嘉峪关市| 常熟市| 北辰区| 鹿泉市| 敖汉旗| 阳原县| 东光县| 苗栗县| 开江县| 景洪市| 尚义县| 乐至县| 兴文县| 罗甸县| 台前县| 尼木县| 卢龙县| 岚皋县| 繁昌县| 环江| 万安县| 普安县|