Rumah  >  Artikel  >  Java  >  Apakah kaedah untuk SpringBoot untuk menyepadukan tomcat?

Apakah kaedah untuk SpringBoot untuk menyepadukan tomcat?

王林
王林ke hadapan
2023-05-14 19:43:141078semak imbas

Spring boot menyokong kontena servlet arus perdana, termasuk tomcat, jeti dan undertow ini boleh disepadukan dengan mudah ke dalam projek kami, mengurangkan beban kerja pembangunan dan operasi serta penyelenggaraan. Pembangunan aplikasi tradisional memerlukan langkah yang rumit: pasangkan tomcat –> ubah suai konfigurasi tomcat –> aplikasi berhijrah. Selepas menggunakan but spring, semuanya menjadi begitu mudah Pembungkusan - java -jar - operasi dan penyelenggaraan, anda hanya memerlukan pakej balang untuk digunakan dan dipasang sesuka hati.

SPI

Sebelum menganalisis kod sumber, mari kita fahami mekanisme musim bunga SPI terlebih dahulu. Kami tahu bahawa jdk menyediakan pelaksanaan SPI lalai (ServiceLoader) untuk memudahkan pengembangan aplikasi, dan dubbo juga mempunyai SPI sendiri. Perkara yang sama berlaku untuk musim bunga. Ia memberikan kami SpringFactoriesLoader, membolehkan pembangun melanjutkan melalui fail META-INF/spring.factories Berikut ialah contoh untuk memudahkan pemahaman tentang

ke bekas spring Untuk melakukan beberapa kerja permulaan, kita boleh menggunakan fungsi SPI yang disediakan oleh spring untuk melengkapkan keperluan ini. ApplicationContextInitializer

Pertama sekali, buat fail

dalam projek Kandungan fail adalah seperti berikut: META-INF/spring.factories

org.springframework.context.ApplicationContextInitializer=

kami Dengan menulis kes ujian lain, kami boleh mendapatkan

yang kami takrifkan melalui SPI. Nampaknya ia adalah fungsi yang sangat mudah, tetapi but spring mengambil kesempatan daripada titik sambungan yang berkuasa ini untuk menyepadukan rangka kerja sumber terbuka yang biasa digunakan untuk kita berdasarkan rangka kerja spring ApplicationContextInitializer

@Test
public void testSpringSpi() {
    List<ApplicationListener> listeners = SpringFactoriesLoader.loadFactories( ApplicationListener.class, 
            ClassUtils.getDefaultClassLoader() );
    System.out.println( listeners );

Mari kita lihat ini sekali lagi

, Kod kunci adalah seperti berikut Ia membaca fail SpringFactoriesLoader dan mencari kelas yang ditentukan oleh parameter kaedah, kemudian mencipta objek contoh yang sepadan dan mengembalikannya. Selain itu, pengisihan juga disokong dan boleh diisih mengikut cara berikut META-INF/spring.factories

  • org.springframework.core.Diperintahkan: Laksanakan antara muka ini

  • org .springframework.core.annotation.Order: Anotasi

  • javax.annotation. Keutamaan: Anotasi

  • public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
        List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
        List<T> result = new ArrayList<T>(factoryNames.size());
        for (String factoryName : factoryNames) {
            result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
        }
        AnnotationAwareOrderComparator.sort(result);
        return result;
Seterusnya, mari analisa spring Bagaimana but menggunakan mekanisme SPI untuk mengintegrasikan tomcat

SpringBoot for Tomcat

Sebelum menganalisis kod sumber penyepaduan tomcat, mari kita fahami EmbeddedServletContainer

EmbeddedServletContainer:

EmbeddedServletContainer: untuk merangkum bekas servlet terbenam, menyediakan antara muka seperti

dan EmbeddedServletContainer untuk mengawal kitaran hayat bekas, dan spring mempunyai pelaksanaan terbina dalam bekas tomcat, jeti dan undertow, seperti yang ditunjukkan dalam gambar rajah kelas Seperti yang ditunjukkan startstop mari kita lihat anotasi

yang paling biasa digunakan dalam but musim bunga Ia ternyata menjadi kompleks berbilang anotasi dan ini

ialah anotasi SpringBootApplication. digunakan oleh but spring untuk konfigurasi automatik

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    // code......
EnableAutoConfigurationKita boleh melihat sejumlah besar konfigurasi SPI dalam modul

, beberapa daripadanya adalah seperti berikut

spring-boot-autoconfigure

# Auto Configure
org. .springframework.boot.autoconfigure.EnableAutoConfiguration=

org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,

Ternyata
anotasi memperkenalkan,

ini kelas konfigurasi bekas servlet terbenam, termasuk tomcat, jeti dan undertow Pada kelas ini, muatkan bekas servlet yang berbeza melalui anotasi EnableAutoConfiguration. Walau bagaimanapun, kelas ini hanya berdaftar EmbeddedServletContainerAutoConfiguration, yang tidak mencukupi untuk membantu kami menyelesaikan semua kekeliruan. Jangan risau, mari lihat gambar rajah kelas @ConditionalOnClass dahulu. TomcatEmbeddedServletContainerFactoryTomcatEmbeddedServletContainerFactorySeperti yang dapat dilihat daripada rajah kelas di atas, ia melaksanakan antara muka berikut:

    EmbeddedServletContainerFactory: Ia adalah corak kilang yang digunakan untuk mencipta
  • , iaitu , digunakan untuk mencipta Bekas Servlet terbenam, hanya terdapat satu kaedah

    dalam antara muka ini EmbeddedServletContainergetEmbeddedServletContainer

  • ConfigurableEmbeddedServletContainer: digunakan untuk mengkonfigurasi
  • , seperti port, laluan konteks, dsb.

    EmbeddedServletContainer

  • menganalisis dua antara muka di atas Ternyata kerja mencipta bekas servlet diselesaikan dengan
Lihat susunan panggilan kaedah

. Kaedah EmbeddedServletContainerFactory ditulis semula dalam getEmbeddedServletContainer, dan kaedah EmbeddedWebApplicationContext dipanggil untuk mencipta bekas servlet Mari kita analisa proses penciptaan ini seterusnya. GenericWebApplicationContext#onRefresh()getEmbeddedServletContainerKod utama adalah seperti berikut (pengendalian pengecualian ditinggalkan):

EmbeddedWebApplicationContext.java
@Override
protected void onRefresh() {
    super.onRefresh();
    createEmbeddedServletContainer();
}
private void createEmbeddedServletContainer() {
    EmbeddedServletContainer localContainer = this.embeddedServletContainer;
    ServletContext localServletContext = getServletContext();
    if (localContainer == null && localServletContext == null) {
        // 从容器中获取bean,如果使用tomcat则返回TomcatEmbeddedServletContainerFactory
        EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
        this.embeddedServletContainer = containerFactory.getEmbeddedServletContainer(getSelfInitializer());
    }
    else if (localServletContext != null) {
        getSelfInitializer().onStartup(localServletContext);
    }
    initPropertySources();

Mari lukis carta alir utama dahulu

Apakah kaedah untuk SpringBoot untuk menyepadukan tomcat?

由上图可知,EmbeddedWebApplicationContext在执行onRefresh方法的时候,首先调用父类的onRefresh,然后从容器中获取EmbeddedServletContainerFactory的实现类。由于我们在 classpath 下面可以获取 tomcat 的 jar 包,因此EmbeddedServletContainerAutoConfiguration会在 spring 容器中注册TomcatEmbeddedServletContainerFactory这个 bean。然后,由它创建TomcatEmbeddedServletContainer,我们来看看具体的创建过程,代码如下所示:

TomcatEmbeddedServletContainerFactory.java
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
        ServletContextInitializer... initializers) {
    Tomcat tomcat = new Tomcat();   // 实例化 apache Tomcat 
    File baseDir = (this.baseDirectory != null ? this.baseDirectory
            : createTempDir("tomcat"));
    tomcat.setBaseDir(baseDir.getAbsolutePath());
    // 创建 Connector 组件,默认使用org.apache.coyote.http11.Http11NioProtocol
    Connector connector = new Connector(this.protocol); 
    tomcat.getService().addConnector(connector);
    // 支持对 Connector 进行自定义设置,比如设置线程池、最大连接数等
    customizeConnector(connector);
    tomcat.setConnector(connector);
    tomcat.getHost().setAutoDeploy(false);
    configureEngine(tomcat.getEngine());
    for (Connector additionalConnector : this.additionalTomcatConnectors) {
        tomcat.getService().addConnector(additionalConnector);
    }
    prepareContext(tomcat.getHost(), initializers);
    return getTomcatEmbeddedServletContainer(tomcat);

首先是实例化Tomcat对象,然后创建Connector组件,并且对Connector进行相关的参数设置,同时也允许我们通过TomcatConnectorCustomizer接口进行自定义的设置。OK,创建了Tomcat实例之后,需要创建TomcatEmbeddedServletContainer,它依赖Tomcat对象,在构造方法中便会启动 Tomcat 容器,从而完成各个组件的启动流程

public TomcatEmbeddedServletContainer(Tomcat tomcat, boolean autoStart) {
    Assert.notNull(tomcat, "Tomcat Server must not be null");
    this.tomcat = tomcat;
    this.autoStart = autoStart;
    initialize();
}
private void initialize() throws EmbeddedServletContainerException {
    synchronized (this.monitor) {
        addInstanceIdToEngineName();
        // Remove service connectors to that protocol binding doesn&#39;t happen yet
        removeServiceConnectors();
        // Start the server to trigger initialization listeners
        this.tomcat.start();
        // We can re-throw failure exception directly in the main thread
        rethrowDeferredStartupExceptions();
        Context context = findContext();
        ContextBindings.bindClassLoader(context, getNamingToken(context),
                    getClass().getClassLoader());
        // Unlike Jetty, all Tomcat threads are daemon threads. We create a
        // blocking non-daemon to stop immediate shutdown
        startDaemonAwaitThread();
    }

Atas ialah kandungan terperinci Apakah kaedah untuk SpringBoot untuk menyepadukan tomcat?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam