Maven項目中使用tomcat啓動

最近學習Tomcat源碼,平時新建maven項目的時候,使用springboot內嵌tomcat啓動,現在需要使用外部tomcat啓動,以便於學習tomcat和spring代碼之間的執行關係。 添加完外部tomcat後突然發現無法將 maven項目的web項目添加到tomcat中。

 

就是通過下圖添加maven的 web項目,如過在JavaEE窗口下,項目中沒有Deployment Descriptor:  的標記可能你的項目是無法添加到tomcat中的。

 

因此你想讓你的項目可以添加到Tomcat中,需要按照下面的步驟來操作自己的項目。

1.首先 鼠標右鍵項目屬性  properties。

2.選擇 Project Facets 進行添加Dynamic Web Module選項,你可以選擇其中的版本信息。

3.應用到項目,最後你就可以添加了。

 

 

按照上面的步驟可能你就可以將項目添加到Tomcat中了,但是你不一定能運行成功,因爲還需要在你的pom文件中添加一些引用:

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
                <version>2.1.1.RELEASE</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
	            <groupId>org.springframework.boot</groupId>
	            <artifactId>spring-boot-starter-web</artifactId>
	        </dependency>

以及在啓動類中做一些改變:

加一個@ServletComponentScan 註解,以及繼承  SpringBootServletInitializer 類,然後重寫 configure(SpringApplicationBuilder springApplicationBuilder)方法。關於爲什麼需要繼承SpringBootServletInitializer 後續可能做出進一步的分析。

 

看一下  SpringBootServletInitializer 的具體實現。這個類實現了WebApplicationInitializer 接口。

此處你只需要知道:

在tomcat啓動的時候會通過java 的SPI機制 加載Spring-web jar目錄下的文件然後加載類

SpringServletContainerInitializer ,然後此類會在tomcat啓動時掉用他的onStartup 方法。

StandardContex初始化時會將實現了 WebApplicationInitializer 接口的類加載到 Context中,後面會調用 SpringServletContainerInitializer 類的onStartup方法時,做爲參數Set<Class<?>> webAppInitializerClasses傳入。後面會調用

WebApplicationInitializer實現類的的方法:

onStartup(ServletContext servletContext)。

想進一步瞭解其中原理可以看我的另一篇文章:

java SPI 機制 在Tomcat,spring-mvc啓動及servlet3.0中的應用  

public abstract class SpringBootServletInitializer implements WebApplicationInitializer {

	protected Log logger; // Don't initialize early

	private boolean registerErrorPageFilter = true;

	/**
	 * Set if the {@link ErrorPageFilter} should be registered. Set to {@code false} if
	 * error page mappings should be handled via the server and not Spring Boot.
	 * @param registerErrorPageFilter if the {@link ErrorPageFilter} should be registered.
	 */
	protected final void setRegisterErrorPageFilter(boolean registerErrorPageFilter) {
		this.registerErrorPageFilter = registerErrorPageFilter;
	}

	@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
		// Logger initialization is deferred in case an ordered
		// LogServletContextInitializer is being used
		this.logger = LogFactory.getLog(getClass());
		WebApplicationContext rootAppContext = createRootApplicationContext(
				servletContext);
		if (rootAppContext != null) {
			servletContext.addListener(new ContextLoaderListener(rootAppContext) {
				@Override
				public void contextInitialized(ServletContextEvent event) {
					// no-op because the application context is already initialized
				}
			});
		}
		else {
			this.logger.debug("No ContextLoaderListener registered, as "
					+ "createRootApplicationContext() did not "
					+ "return an application context");
		}
	}

	protected WebApplicationContext createRootApplicationContext(
			ServletContext servletContext) {
		SpringApplicationBuilder builder = createSpringApplicationBuilder();
		builder.main(getClass());
		ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
		if (parent != null) {
			this.logger.info("Root context already created (using as parent).");
			servletContext.setAttribute(
					WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
			builder.initializers(new ParentContextApplicationContextInitializer(parent));
		}
		builder.initializers(
				new ServletContextApplicationContextInitializer(servletContext));
		builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);
		builder = configure(builder);
		builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext));
		SpringApplication application = builder.build();
		if (application.getAllSources().isEmpty() && AnnotationUtils
				.findAnnotation(getClass(), Configuration.class) != null) {
			application.addPrimarySources(Collections.singleton(getClass()));
		}
		Assert.state(!application.getAllSources().isEmpty(),
				"No SpringApplication sources have been defined. Either override the "
						+ "configure method or add an @Configuration annotation");
		// Ensure error pages are registered
		if (this.registerErrorPageFilter) {
			application.addPrimarySources(
					Collections.singleton(ErrorPageFilterConfiguration.class));
		}
		return run(application);
	}

	/**
	 * Returns the {@code SpringApplicationBuilder} that is used to configure and create
	 * the {@link SpringApplication}. The default implementation returns a new
	 * {@code SpringApplicationBuilder} in its default state.
	 * @return the {@code SpringApplicationBuilder}.
	 * @since 1.3.0
	 */
	protected SpringApplicationBuilder createSpringApplicationBuilder() {
		return new SpringApplicationBuilder();
	}

	/**
	 * Called to run a fully configured {@link SpringApplication}.
	 * @param application the application to run
	 * @return the {@link WebApplicationContext}
	 */
	protected WebApplicationContext run(SpringApplication application) {
		return (WebApplicationContext) application.run();
	}

	private ApplicationContext getExistingRootWebApplicationContext(
			ServletContext servletContext) {
		Object context = servletContext.getAttribute(
				WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
		if (context instanceof ApplicationContext) {
			return (ApplicationContext) context;
		}
		return null;
	}

	/**
	 * Configure the application. Normally all you would need to do is to add sources
	 * (e.g. config classes) because other settings have sensible defaults. You might
	 * choose (for instance) to add default command line arguments, or set an active
	 * Spring profile.
	 * @param builder a builder for the application context
	 * @return the application builder
	 * @see SpringApplicationBuilder
	 */
	protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
		return builder;
	}

	private static final class WebEnvironmentPropertySourceInitializer
			implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {

		private final ServletContext servletContext;

		private WebEnvironmentPropertySourceInitializer(ServletContext servletContext) {
			this.servletContext = servletContext;
		}

		@Override
		public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
			ConfigurableEnvironment environment = event.getEnvironment();
			if (environment instanceof ConfigurableWebEnvironment) {
				((ConfigurableWebEnvironment) environment)
						.initPropertySources(this.servletContext, null);
			}
		}

		@Override
		public int getOrder() {
			return Ordered.HIGHEST_PRECEDENCE;
		}

	}

}

 

代碼如下: 

@SpringBootApplication(scanBasePackages = {"com.hcgao","com.boot"})   
//@ComponentScan(basePackages = {"com.hcgao.*","com.boot.**"})
//@EnableAsync
@ServletComponentScan
public class Application extends SpringBootServletInitializer{
	
	@Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder springApplicationBuilder){
        return springApplicationBuilder.sources(Application.class);
    }
	
	public static void main(String[] args) throws Exception {
         SpringApplication.run(Application.class, args);
     }
}

 

添加完成後,如果你通過tomcat啓動成功,那麼祝賀你你成功了。
但是我在這個地方又遇到了一點小問題。

下面看一下日誌,tomcat雖然啓動了,但是沒有啓動springBoot項目中的信息。

說明我們的springBoot項目並沒有啓動成功。

很明顯是因爲tomcat啓動時沒有掃描到 Maven中的jar,也沒有加載到 spring-web的包

所以你需要通過下面的操作,將maven掃描包加載到項目中:

最後啓動結果:

五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: Server.服務器版本:     Apache Tomcat/9.0.34
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 服務器構建:            Apr 3 2020 12:02:52 UTC
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 服務器版本號(:9.0.34.0
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: OS Name:               Windows 10
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: OS.版本:               10.0
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 架構:                  amd64
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: Java 環境變量:         H:\Program Files\Java\jdk1.8.0_211\jre
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: JVM 版本:              1.8.0_211-b12
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: JVM.供應商:            Oracle Corporation
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: CATALINA_BASE:[D:\gaohaichneg_jiagou\.metadata\.plugins\org.eclipse.wst.server.core\tmp0]
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: CATALINA_HOME:         G:\apache-tomcat-9.0.34
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行參數:[-Dcatalina.base=D:\gaohaichneg_jiagou\.metadata\.plugins\org.eclipse.wst.server.core\tmp0]
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行參數:[-Dcatalina.home=G:\apache-tomcat-9.0.34]
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行參數:[-Dwtp.deploy=D:\gaohaichneg_jiagou\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps]
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行參數:[-Djava.endorsed.dirs=G:\apache-tomcat-9.0.34\endorsed]
五月 02, 2020 3:42:15 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行參數:[-Dfile.encoding=GBK]
五月 02, 2020 3:42:15 下午 org.apache.catalina.core.AprLifecycleListener lifecycleEvent
信息: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [H:\Program Files\Java\jdk1.8.0_211\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;H:/Program Files/Java/jre1.8.0_211/bin/server;H:/Program Files/Java/jre1.8.0_211/bin;H:/Program Files/Java/jre1.8.0_211/lib/amd64;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\System32\wbem;H:\Program Files\Java\jdk1.8.0_211\bin;H:\Program Files\Java\jdk1.8.0_211\jre\bin;H:\Program Files\mysql-5.7.16-winx64\bin;E:\zookeeper-3.4.6\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;F:\oxygenEnvir\apache-maven-3.3.9\bin;F:\oxygenEnvir\nodeJs\;F:\oxygenEnvir\nodeJs\node_global;H:\Program Files\Git\cmd;H:\Program Files\Anaconda311111;C:\WINDOWS\System32\OpenSSH\;H:\AppData\Local\Programs\Python\Python37;D:\huanjing\gradle-6.0\bin;H:\Program Files\erl10.3\bin;H:\Program Files\RabbitMQ Server\rabbitmq_server-3.8.1\sbin;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;H:\Program Files\MATLAB\R2018a\runtime\win64;H:\Program Files\MATLAB\R2018a\bin;C:\Users\高海成\AppData\Local\Programs\Python\Python36\Scripts\;C:\Users\高海成\AppData\Local\Programs\Python\Python36\;H:\AppData\Local\Programs\Python\Python37\Scripts\;H:\AppData\Local\Programs\Python\Python37\;H:\AppData\Local\Programs\Python\Python36\Scripts\;H:\AppData\Local\Programs\Python\Python36\;C:\Users\高海成\AppData\Local\Microsoft\WindowsApps;C:\Users\高海成\AppData\Local\GitHubDesktop\bin;C:\Users\高海成\AppData\Roaming\npm;F:\oxygenEnvir\VS Code\bin;C:\Users\高海成\AppData\Local\Microsoft\WindowsApps;C:\Users\高海成\AppData\Local\BypassRuntm;h:\Program Files\JetBrains\PyCharm Community Edition 2019.3.1\bin;;D:\Users\YUNWEN\eclipse;;.]
五月 02, 2020 3:42:16 下午 org.apache.coyote.AbstractProtocol init
信息: 初始化協議處理器 ["http-nio-8080"]
五月 02, 2020 3:42:16 下午 org.apache.catalina.startup.Catalina load
信息: 服務器在[1,485]毫秒內初始化
五月 02, 2020 3:42:16 下午 org.apache.catalina.core.StandardService startInternal
信息: Starting service [Catalina]
五月 02, 2020 3:42:16 下午 org.apache.catalina.core.StandardEngine startInternal
信息: 正在啓動 Servlet 引擎:[Apache Tomcat/9.0.34]
五月 02, 2020 3:42:23 下午 org.apache.jasper.servlet.TldScanner scanJars
信息: 至少有一個JAR被掃描用於TLD但尚未包含TLD。 爲此記錄器啓用調試日誌記錄,以獲取已掃描但未在其中找到TLD的完整JAR列表。 在掃描期間跳過不需要的JAR可以縮短啓動時間和JSP編譯時間。
五月 02, 2020 3:42:23 下午 org.apache.catalina.core.ApplicationContext log
信息: 2 Spring WebApplicationInitializers detected on classpath
Application Version: ${ruoyi.version}
Spring Boot Version: 2.1.1.RELEASE
////////////////////////////////////////////////////////////////////
//                          _ooOoo_                               //
//                         o8888888o                              //
//                         88" . "88                              //
//                         (| ^_^ |)                              //
//                         O\  =  /O                              //
//                      ____/`---'\____                           //
//                    .'  \\|     |//  `.                         //
//                   /  \\|||  :  |||//  \                        //
//                  /  _||||| -:- |||||-  \                       //
//                  |   | \\\  -  /// |   |                       //
//                  | \_|  ''\---/''  |   |                       //
//                  \  .-\__  `-`  ___/-. /                       //
//                ___`. .'  /--.--\  `. . ___                     //
//              ."" '<  `.___\_<|>_/___.'  >'"".                  //
//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
//      ========`-.____`-.___\_____/___.-`____.-'========         //
//                           `=---='                              //
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
//             佛祖保佑       永不宕機      永無BUG               //
////////////////////////////////////////////////////////////////////
2020-05-02 15:42:25,587 [main] INFO  com.boot.Application - Starting Application on DESKTOP-1H6IM7E with PID 2300 (D:\gaohaichneg_jiagou\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\hcgao-web\WEB-INF\classes started by 高海成 in D:\Users\YUNWEN\eclipse)
2020-05-02 15:42:25,597 [main] INFO  com.boot.Application - No active profile set, falling back to default profiles: default
2020-05-02 15:42:27,808 [main] INFO  o.s.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'asyncConfig' of type [com.boot.config.AsyncConfig$$EnhancerBySpringCGLIB$$79d742b2] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-05-02 15:42:28,017 [main] INFO  org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/hcgao-web] - Initializing Spring embedded WebApplicationContext
2020-05-02 15:42:28,021 [main] INFO  org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 2350 ms
2020-05-02 15:42:30,176 [main] INFO  org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor - Initializing ExecutorService 'applicationTaskExecutor'
2020-05-02 15:42:31,316 [main] WARN  org.thymeleaf.templatemode.TemplateMode - [THYMELEAF][main] Template Mode 'HTML5' is deprecated. Using Template Mode 'HTML' instead.
2020-05-02 15:42:31,406 [main] INFO  org.springframework.boot.autoconfigure.web.servlet.WelcomePageHandlerMapping - Adding welcome page template: index
2020-05-02 15:42:31,684 [main] INFO  com.boot.Application - Started Application in 7.905 seconds (JVM running for 16.59)
2020-05-02 15:42:31,706 [main] INFO  org.apache.coyote.http11.Http11NioProtocol - 開始協議處理句柄["http-nio-8080"]
2020-05-02 15:42:31,716 [main] INFO  org.apache.catalina.startup.Catalina - Server startup in [14,903] milliseconds

 

最後終於啓動成功了。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章