предисловие
существуетПервый опыт Spring BootВ этой статье мы научились быстро запускатьSpring Boot
программа, иSpring Boot
Также поддерживаются традиционные методы развертывания: упакуйте проект какWAR
, затем поWeb
Сервер загружается и запускается, на этот раз сTomcat
Например, давайте быстро научимся использоватьWAR
способ развертыванияSpring Boot
проект, код размещен наGithubи проведите простой анализ исходного кода.
текст
использоватьSpring Initializrбазовая загрузка инструментаSpring Boot
техника, выборMaven
способ сборки, версия официальная версия 1.5.16, только выберите одинWeb
полагаться.
наследоватьSpringBootServletInitializer
нагрузка
После открытия загруженного проекта запустите классSpringbootTomcatApplication
изменять, наследоватьSpringBootServletInitializer
Этот абстрактный класс и переопределить метод родительского классаSpringApplicationBuilder configure(SpringApplicationBuilder builder)
.
@SpringBootApplication
public class SpringbootTomcatApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringbootTomcatApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(SpringbootTomcatApplication.class, args);
}
}
SpringBootServletInitializer
класс будет вServlet
Когда контейнер запускает программу, это позволяет нам настроить конфигурацию программы, и здесь нам нужно будет сделатьServlet
Этот класс загружается, когда контейнер запускает программу.
Измените метод упаковки на WAR
следующий вpom.xml
В файле измените метод упаковки наWAR
,ПозволятьMaven
при построении сWAR
способ генерировать.
<groupId>com.one</groupId>
<artifactId>springboot-tomcat</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
Также обратите внимание, что: Для обеспечения встроенногоservlet
Контейнер не влияет на контейнер сервлета, который развертывает файл войны, вот онTomcat
. Нам также необходимо встроитьservlet
Зависимости контейнера отмечены какprovided
.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
Реализовать обработку запросов на отдых
чтобы доказатьWAR
Если развертывание прошло успешно, мы реализуем самую базовую обработкуWeb
Для требуемой функциональности добавьте некоторые в класс запускаSpring MVC
код
@SpringBootApplication
@RestController
public class SpringbootTomcatApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringbootTomcatApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(SpringbootTomcatApplication.class, args);
}
@RequestMapping(value = "/")
public String hello() {
return "hello tomcat";
}
}
Упаковка проекта
Готов упаковать сейчасSpring Boot
запрограммировать вWAR
, тогда пустьTomcat
Сервер загружен, используйте команду сборки в текущем пути проекта
mvn clean package
ПоявлятьсяBUILD SUCCESS
значит упаковка удалась
Затем вы можете проецироватьtarget
См. сгенерированный каталог вWAR
.
Развернуть Tomcat
будетspringboot-tomcat-0.0.1-SNAPSHOT.war
Поместите его в папку программы Tomcat**webapps**
вниз, затем бегитеTomcat
, после успешного запуска можно войти в браузереhttp://localhost:8080/springboot-tomcat-0.0.1-SNAPSHOT/, запросите этот простойWeb
программа.
сюда,WAR
способ развертыванияSpring Boot
Программа завершена 🎉🎉🎉
Анализ исходного кода
После завершения этого у меня не может не возникнуть вопрос: почему унаследовалSpringBootServletInitializer
class и переопределить его метод configure, чтобы развернуть его в режиме войны?С вопросом мы ищем ответ с точки зрения исходного кода.
Установите точку останова в методе, переопределяемом классом запуска SpringbootTomcatApplication, и просмотрите процесс вызова метода, когда Tomcat запускает проект.
Запустите проект в режиме отладки, когда вы дойдете до этой строки кода, вы увидите два важных класса.SpringBootServletInitializer
а такжеSpringServletContainerInitializer
.
Как видно из рисунка вызов метода configure находится в родительском классеcreateRootApplicationContext
, конкретный код выглядит следующим образом, некритические части опущены, а важные закомментированы.
protected WebApplicationContext createRootApplicationContext(
ServletContext servletContext) {
SpringApplicationBuilder builder = createSpringApplicationBuilder(); // 新建用于构建SpringApplication 实例的 builder
builder.main(getClass());
// ....
builder.initializers(
new ServletContextApplicationContextInitializer(servletContext));
builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);
builder = configure(builder); // 调用子类方法,配置当前 builder
builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext));
SpringApplication application = builder.build(); // 构建 SpringApplication 实例
if (application.getSources().isEmpty() && AnnotationUtils
.findAnnotation(getClass(), Configuration.class) != null) {
application.getSources().add(getClass());
}
//...
return run(application); // 运行 SpringApplication 实例
}
SpringApplicationBuilder
Экземпляры должны следовать шаблону проектирования компоновщика для завершенияSpringApplication
построить сборку.
а такжеcreateRootApplicationContext
Вызов метода по-прежнему выполняется в этом классе, который более знаком, поскольку традиционныйSpring Web
Запуск проекта также создаетWebApplicationContext
пример.
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// Logger initialization is deferred in case a ordered
// LogServletContextInitializer is being used
this.logger = LogFactory.getLog(getClass());
WebApplicationContext rootAppContext = createRootApplicationContext(
servletContext); // 创建一个 WebApplicationContext 实例.
// ...
}
Вот опять проблемаonStartup
Как реализуется метод?SpringServletContainerInitializer
Появляется класс.
SpringServletContainerInitializer
реализация классаServlet 3.0
нормативныйServletContainerInitializer
интерфейс, что означает, что когдаServlet
Когда контейнер запустится, он вызоветServletContainerInitializer
интерфейсonStartup
Методы уведомляют классы, реализующие этот интерфейс.
public interface ServletContainerInitializer {
void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException;
}
Теперь давайте посмотримSpringServletContainerInitializer
изonStarup
Конкретная реализация метода выглядит следующим образом, в ключевой строке кода 23 ~ 24.initializers
ЯвляетсяLinkedList
коллекция, со всеми реализациямиWebApplicationInitializer
Экземпляры интерфейса, перебор здесь вызовет соответствующийonStartup
передача методаServletContext
пример для завершенияWeb
Уведомление о запуске сервера.
@Override
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
// 提取webAppInitializerClasses集合中 实现 WebApplicationInitializer 接口的实例
initializers.add((WebApplicationInitializer) waiClass.newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
// ...
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext); // 调用所有实现 WebApplicationInitializer 实例的onStartup 方法
}
}
отследить выполнение доSpringServletContainerInitializer
В строке 22 класса мы видим, что коллекция содержит наш класс запуска, поэтому мы, наконец, вызываем его родительский классonStartup
метод завершенWebApplicationContext
создание экземпляра.
Увидев это, давайте подытожим процессы вызова этих классов и разберем их.Spring Boot
программаWAR
Способ запуска процесса:
SpringServletContainerInitializer#onStartup
=>SpringBootServletInitializer#onStartup
=> ``SpringBootServletInitializer#createRootApplicationContext =>
SpringbootTomcatApplication#configure`
Кроме того, я также получил один балл: при выполненииSpringBootServletInitializer
изcreateRootApplicationContext
В конце метода вызовитеrun(application)
.
Это также показывает, что когдаWAR
способ развертыванияSpring Boot
проект, фиксированный сгенерированныйMain
Метод больше не будет выполняться и может быть удален.
//当项目以WAR方式部署时,这个方法就是无用代码
public static void main(String[] args) {
SpringApplication.run(SpringbootTomcatApplication.class, args);
}
Эпилог
Эта статья в основном учит, как сделатьSpring Boot
кWAR
способ начать и выполнить простой анализ исходного кода, чтобы помочь нам лучше понятьSpring Boot
.Надеюсь, это поможет, в дальнейшем будет больше реальных боев и анализов, так что следите за обновлениями.