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.
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
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 );
, 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
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;
EmbeddedServletContainer:<🎜 menggunakan
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 start
stop
mari kita lihat anotasi
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......
EnableAutoConfiguration
Kita boleh melihat sejumlah besar konfigurasi SPI dalam modul , beberapa daripadanya adalah seperti berikutspring-boot-autoconfigure
org. .springframework.boot.autoconfigure.EnableAutoConfiguration=anotasi memperkenalkan,org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,
Ternyata
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. TomcatEmbeddedServletContainerFactory
TomcatEmbeddedServletContainerFactory
Seperti yang dapat dilihat daripada rajah kelas di atas, ia melaksanakan antara muka berikut:
dalam antara muka ini EmbeddedServletContainer
getEmbeddedServletContainer
EmbeddedServletContainer
. Kaedah EmbeddedServletContainerFactory
ditulis semula dalam getEmbeddedServletContainer
, dan kaedah EmbeddedWebApplicationContext
dipanggil untuk mencipta bekas servlet Mari kita analisa proses penciptaan ini seterusnya. GenericWebApplicationContext#onRefresh()
getEmbeddedServletContainer
Kod 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
由上图可知,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'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!