SpringBoot 내장 tomcat 작 동 원리 상세 설명
16768 단어 SpringBoot내장tomcat시동 을 걸다
SpringBoot 의 개발 자 는 대중 프로그램 원숭이 들 을 위해 복 지 를 도모 하고 있 습 니 다.모 두 를 게으름뱅이 로 만 들 었 습 니 다.xml 는 설정 하지 않 고 tomcat 도 게 으 른 설정 을 했 습 니 다.전형 적 인 원 키 로 시스템 을 작 동 시 켰 습 니 다.그러면 tomcat 는 springboot 에서 어떻게 작 동 합 니까?
tomcat 내장
개발 단 계 는 우리 에 게 내 장 된 tomcat 를 사용 하 는 것 이 매우 충분 하 며,물론 Jetty 도 사용 할 수 있다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
@SpringBootApplication
public class MySpringbootTomcatStarter{
public static void main(String[] args) {
Long time=System.currentTimeMillis();
SpringApplication.run(MySpringbootTomcatStarter.class);
System.out.println("=== :"+(System.currentTimeMillis()-time)+"===");
}
}
여 기 는 main 함수 입구 입 니 다.두 개의 코드 가 가장 눈 에 띄 는데 그것 이 바로 SpringBootApplication 주해 와 SpringApplication.run()방법 입 니 다.생산 을 발표 하 다
발표 할 때 현재 대부분의 방법 은 내 장 된 tomcat 를 제외 하고 기와 가방(war)을 친 다음 에 생산 된 tomcat 에 배치 하 는 것 입 니 다.좋 습 니 다.그럼 포장 할 때 어떻게 처리 해 야 합 니까?
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- tomcat -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- servlet-api --->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
main 함 수 를 업데이트 합 니 다.주로 SpringBootServletInitializer 를 계승 하고 configure()방법 을 다시 씁 니 다.
@SpringBootApplication
public class MySpringbootTomcatStarter extends SpringBootServletInitializer {
public static void main(String[] args) {
Long time=System.currentTimeMillis();
SpringApplication.run(MySpringbootTomcatStarter.class);
System.out.println("=== :"+(System.currentTimeMillis()-time)+"===");
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(this.getClass());
}
}
main 함수 부터 말하자면
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
--여기 서 run 방법 은 ConfigurableApplication Context 를 되 돌려 줍 니 다.
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
public ConfigurableApplicationContext run(String... args) {
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// banner, , logo
Banner printedBanner = this.printBanner(environment);
//
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
//
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//
this.refreshContext(context);
//
this.afterRefresh(context, applicationArguments);
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
}
}
tomcat 가 SpringBoot 에서 어떻게 시작 되 는 지 알 고 싶 으 면 run 방법 에 서 는 응용 컨 텍스트(createapplication Context)를 만 들 고 컨 텍스트(refreshContext)를 새로 고침 하 는 데 중점 을 두 고 있 습 니 다.상하 문 생 성
//
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch(this.webApplicationType) {
case SERVLET:
// AnnotationConfigServletWebServerApplicationContext
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
break;
case REACTIVE:
contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
break;
default:
contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
}
} catch (ClassNotFoundException var3) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
}
}
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}
AnnotationConfigServletWebServerApplication Context 클래스 를 만 듭 니 다.한편,AnnotationConfigServletWebServerApplication Context 류 는 ServletWebServerApplication Context 를 계승 하 였 으 며,이 종 류 는 최종 적 으로 AbstractApplication Context 를 통합 하 였 다.
문맥 새로 고침
//SpringApplication.java
//
private void refreshContext(ConfigurableApplicationContext context) {
this.refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException var3) {
}
}
}
// AbstractApplicationContext.refresh()
protected void refresh(ApplicationContext applicationContext) {
((AbstractApplicationContext)applicationContext).refresh();
}
//AbstractApplicationContext.java
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
// onRefresh() , :ServletWebServerApplicationContext, onRefresh()
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
//ServletWebServerApplicationContext.java
// ,this.createWebServer, 。
protected void onRefresh() {
super.onRefresh();
try {
this.createWebServer();
} catch (Throwable var2) {
}
}
//ServletWebServerApplicationContext.java
// webServer, tomcat, ServletWebServerFactory , ServletWebServerFactory
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = this.getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = this.getWebServerFactory();
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
} else if (servletContext != null) {
try {
this.getSelfInitializer().onStartup(servletContext);
} catch (ServletException var4) {
}
}
this.initPropertySources();
}
//
public interface ServletWebServerFactory {
WebServer getWebServer(ServletContextInitializer... initializers);
}
//
AbstractServletWebServerFactory
JettyServletWebServerFactory
TomcatServletWebServerFactory
UndertowServletWebServerFactory
여기 ServletWebServerFactory 인터페이스 에 4 개의 실현 클래스 가 있 습 니 다.그 중에서 우리 가 자주 사용 하 는 것 은 두 가지 가 있 는데 그것 이 바로 TomcatServletWebServerFactory 와 Jetty ServletWebServerFactory 이다.
//TomcatServletWebServerFactory.java
// tomcat, TomcatServletWebServerFactory。 tomcat 。
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
// Connector
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(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 getTomcatWebServer(tomcat);
}
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
return new TomcatWebServer(tomcat, getPort() >= 0);
}
//Tomcat.java
// Engine , , tomcat , engine 。
public Engine getEngine() {
Service service = getServer().findServices()[0];
if (service.getContainer() != null) {
return service.getContainer();
}
Engine engine = new StandardEngine();
engine.setName( "Tomcat" );
engine.setDefaultHost(hostname);
engine.setRealm(createDefaultRealm());
service.setContainer(engine);
return engine;
}
//Engine ,Host Engine ,Context Host ,Wrapper Context
getWebServer 라 는 방법 은 Tomcat 대상 을 만 들 고 두 가지 중요 한 일 을 했 습 니 다.Connector 대상 을 tomcat 에 추가 하고 configureEngine(tomcat.getEngine();getWebServer 방법 은 TomcatWebServer 를 되 돌려 줍 니 다.
//TomcatWebServer.java
// TomcatWebServer
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
initialize();
}
private void initialize() throws WebServerException {
//
logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
synchronized (this.monitor) {
try {
addInstanceIdToEngineName();
Context context = findContext();
context.addLifecycleListener((event) -> {
if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
removeServiceConnectors();
}
});
//=== tomcat ===
this.tomcat.start();
rethrowDeferredStartupExceptions();
try {
ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
}
catch (NamingException ex) {
}
//
startDaemonAwaitThread();
}
catch (Exception ex) {
stopSilently();
destroySilently();
throw new WebServerException("Unable to start embedded Tomcat", ex);
}
}
}
//Tomcat.java
public void start() throws LifecycleException {
getServer();
server.start();
}
// server.start TomcatWebServer
public void stop() throws LifecycleException {
getServer();
server.stop();
}
//TomcatWebServer.java
// tomcat
@Override
public void start() throws WebServerException {
synchronized (this.monitor) {
if (this.started) {
return;
}
try {
addPreviouslyRemovedConnectors();
Connector connector = this.tomcat.getConnector();
if (connector != null && this.autoStart) {
performDeferredLoadOnStartup();
}
checkThatConnectorsHaveStarted();
this.started = true;
// , yml ,
logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
+ getContextPath() + "'");
}
catch (ConnectorStartFailedException ex) {
stopSilently();
throw ex;
}
catch (Exception ex) {
throw new WebServerException("Unable to start embedded Tomcat server", ex);
}
finally {
Context context = findContext();
ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
}
}
}
// tomcat
@Override
public void stop() throws WebServerException {
synchronized (this.monitor) {
boolean wasStarted = this.started;
try {
this.started = false;
try {
stopTomcat();
this.tomcat.destroy();
}
catch (LifecycleException ex) {
}
}
catch (Exception ex) {
throw new WebServerException("Unable to stop embedded Tomcat", ex);
}
finally {
if (wasStarted) {
containerCounter.decrementAndGet();
}
}
}
}
첨부:tomcat 꼭대기 층 구조 도tomcat 최상 위 용 기 는 서버 로 전체 서버 를 대표 하 며 하나의 서버 는 여러 개의 서 비 스 를 포함 합 니 다.위의 그림 에서 볼 수 있 듯 이 Service 는 주로 여러 개의 Connector 와 하나의 Container 를 포함한다.커 넥 터 는 연결 과 관련 된 일 을 처리 하고 소켓 에서 Request 와 Response 로 전환 합 니 다.Container 는 Servlet 을 패키지 하고 관리 하 며 구체 적 인 Request 요청 을 처리 하 는 데 사 용 됩 니 다.그렇다면 앞서 언급 한 Engine>Host>Context>Wrapper 용 기 는 어떻게 된 것 일 까?다음 그림 을 보 겠 습 니 다.
다시 말 하면 하나의 tomcat 는 하나의 서버 만 포함 하고 하나의 서버 는 여러 개의 서 비 스 를 포함 할 수 있 으 며 하나의 Service 는 하나의 Container 만 있 지만 여러 개의 Connector 가 있 습 니 다.이런 서 비 스 는 여러 개의 연결 을 처리 할 수 있 습 니 다.
여러 개의 커 넥 터 와 하나의 Container 는 하나의 서 비 스 를 형성 하고 Service 가 있 으 면 대외 적 으로 서 비 스 를 제공 할 수 있 습 니 다.그러나 Service 가 서 비 스 를 제공 하려 면 반드시 숙주 환경 을 제공 해 야 합 니 다.그러면 Server 가 아 닙 니 다.그래서 전체 tomcat 의 성명 주 기 는 Server 에 의 해 제 어 됩 니 다.
총결산
SpringBoot 의 시작 은 주로 실 용화 SpringApplication 을 통 해 시 작 됩 니 다.시작 과정 은 주로 다음 과 같은 몇 가지 일 을 했 습 니 다.속성 설정,감청 기 가 져 오기,발표 응용 프로그램 시작 이벤트 초기,시작 입력 매개 변수,설정 환경,출력 배 너,컨 텍스트 생 성,프 리 처리 컨 텍스트,컨 텍스트 새로 고침,컨 텍스트 새로 고침,발표 응용 프로그램 시작 이벤트,응용 프로그램 시작 완료 이벤트 발표.SpringBoot 에서 tomcat 를 시작 하 는 작업 은 다음 단 계 를 갱신 합 니 다.한편,tomcat 의 시작 은 주로 두 개의 구성 요 소 를 예화 하 는 것 입 니 다.Connector,Container,하나의 tomcat 인 스 턴 스 는 하나의 서버 이 고 하나의 서버 는 여러 개의 서 비 스 를 포함 합 니 다.즉,여러 개의 응용 프로그램 입 니 다.모든 Service 는 여러 개의 Connector 와 하나의 Container 를 포함 하고 하나의 Container 아래 에는 여러 개의 키 용기 가 포함 되 어 있 습 니 다.
SpringBoot 내 장 된 tomcat 작 동 원리 에 대한 상세 한 설명 은 여기까지 입 니 다.더 많은 SpringBoot 내 장 된 tomcat 작 동 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
【Java・SpringBoot・Thymeleaf】 에러 메세지를 구현(SpringBoot 어플리케이션 실천편 3)로그인하여 사용자 목록을 표시하는 응용 프로그램을 만들고, Spring에서의 개발에 대해 공부하겠습니다 🌟 마지막 데이터 바인딩에 계속 바인딩 실패 시 오류 메시지를 구현합니다. 마지막 기사🌟 src/main/res...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.