Tomcat 소스 코드 분석의 서버 와 Lifecycle 의 디자인 과 구현
됐어. 잡담 은 그만 하고...
라 이 프 사이클 의 개념 부터...
이것 은 Jetty 에 도 있 습 니 다. 그룹 이 하나의 구성 요소 의 생명 주 기 를 유지 하 는 데 사용 된다 면, 예 를 들 어 start, stop 같은 것 입 니 다.
또한 lifecycle 개념 이 있 는 구성 요소 에 대해 서도 일반적으로 listener 개념 이 있 으 며, 구성 요소 의 상태 가 바 뀌 었 을 때 listener 가 응답 할 수 있 습 니 다.
자, 우선 최상 위 라 이 프 사이클 인터페이스의 정 의 를 살 펴 보 자.
//
public interface Lifecycle {
//
public static final String BEFORE_INIT_EVENT = "before_init";
/**
* The LifecycleEvent type for the "component after init" event.
*/
public static final String AFTER_INIT_EVENT = "after_init";
/**
* The LifecycleEvent type for the "component start" event.
*/
public static final String START_EVENT = "start";
/**
* The LifecycleEvent type for the "component before start" event.
*/
public static final String BEFORE_START_EVENT = "before_start";
/**
* The LifecycleEvent type for the "component after start" event.
*/
public static final String AFTER_START_EVENT = "after_start";
/**
* The LifecycleEvent type for the "component stop" event.
*/
public static final String STOP_EVENT = "stop";
/**
* The LifecycleEvent type for the "component before stop" event.
*/
public static final String BEFORE_STOP_EVENT = "before_stop";
/**
* The LifecycleEvent type for the "component after stop" event.
*/
public static final String AFTER_STOP_EVENT = "after_stop";
/**
* The LifecycleEvent type for the "component after destroy" event.
*/
public static final String AFTER_DESTROY_EVENT = "after_destroy";
/**
* The LifecycleEvent type for the "component before destroy" event.
*/
public static final String BEFORE_DESTROY_EVENT = "before_destroy";
/**
* The LifecycleEvent type for the "periodic" event.
*/
public static final String PERIODIC_EVENT = "periodic";
public static final String CONFIGURE_START_EVENT = "configure_start";
public static final String CONFIGURE_STOP_EVENT = "configure_stop";
// --------------------------------------------------------- Public Methods
/**
* Add a LifecycleEvent listener to this component.
*
* @param listener The listener to add
*/
//
public void addLifecycleListener(LifecycleListener listener);
/**
* Get the life cycle listeners associated with this life cycle. If this
* component has no listeners registered, a zero-length array is returned.
*/
//
public LifecycleListener[] findLifecycleListeners();
/**
* Remove a LifecycleEvent listener from this component.
*
* @param listener The listener to remove
*/
//
public void removeLifecycleListener(LifecycleListener listener);
//
public void init() throws LifecycleException;
//
public void start() throws LifecycleException;
//
public void stop() throws LifecycleException;
/**
* Prepare to discard the object. The following {@link LifecycleEvent}s will
* be fired in the following order:
* <ol>
* <li>DESTROY_EVENT: On the successful completion of component
* destruction.</li>
* </ol>
*
* @exception LifecycleException if this component detects a fatal error
* that prevents this component from being used
*/
//
public void destroy() throws LifecycleException;
/**
* Obtain the current state of the source component.
*
* @return The current state of the source component.
*/
//
public LifecycleState getState();
/**
* Obtain a textual representation of the current component state. Useful
* for JMX.
*/
//
public String getStateName();
}
비교적 간단 한 것 이 좋 습 니 다. 먼저 기본 적 인 상태 와 사건 의 정 의 를 내 린 다음 에 기본 적 인 조작 입 니 다. 예 를 들 어 listener 를 추가 하고 listener 를 제거 하 며 시작 하고 멈 추 는 등 입 니 다.다 비교적 일반적인 편 인 데...
다음은 라 이 프 사이클 의 추상 층, 라 이 프 사이클 베이스...
이것 은 구체 적 으로 그것 의 실현 코드 를 배려 하지 않 는 다.LifecycleBase 는 LifeCycle 인 터 페 이 스 를 직접 계승 합 니 다. 여 기 는 주로 중간 에 listener 를 추가 하고 listener 를 제거 하 는 작업 을 실 현 했 습 니 다. 여 기 는 listener 의 용기 로 확장 되 었 음 을 초보 적 으로 이해 할 수 있 습 니 다.
또한 LifecycleBase 의 정의 에 서 는 기본 적 인 시작 을 확장 하고 작업 을 중단 합 니 다.
예 를 들 어 구성 요소 가 시 작 될 때 현재 구성 요소 의 상 태 를 변경 하고 해당 하 는 listener 를 호출 해 야 합 니 다.여기 서 초기 화 하 는 방법 으로 예 를 들 어 보 자.
// init , ,
@Override
public final synchronized void init() throws LifecycleException {
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
setStateInternal(LifecycleState.INITIALIZING, null, false); // INITIALIZING
try {
initInternal(); // ,
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(
sm.getString("lifecycleBase.initFail",toString()), t);
}
setStateInternal(LifecycleState.INITIALIZED, null, false); // INITIALIZED
}
// ,
protected abstract void initInternal() throws LifecycleException;
이 코드 는 쉽게 이해 할 수 있 을 것 입 니 다. 현재 구성 요소 의 장 착 을 검증 하고 구성 요소 의 상 태 를 수정 하 는 것 이 아 닙 니 다. 물론 구성 요소 의 상 태 를 설정 할 때 listener 호출 도 수반 합 니 다.
마지막 으로 initInternal 방법 을 사용 하여 초기 화 합 니 다. 물론 이 방법 은 구체 적 인 하위 클래스 에서 이 루어 져 야 합 니 다...
또한 여기 에는 비교적 특수 한 LifeCycle 의 추상 층 인 LifecycleMBeanBase 도 소개 해 야 한다. 추상 적 인 LifecycleBase 유형 을 계승 했다. 사실 여기 서 이름 을 보면 이 추상 층 이 무슨 일 을 해 야 하 는 지 알 수 있 을 것 이다.코드 보기:
protected void initInternal() throws LifecycleException {
// If oname is not null then registration has already happened via
// preRegister().
if (oname == null) {
mserver = Registry.getRegistry(null, null).getMBeanServer(); // mbserver
oname = register(this, getObjectNameKeyProperties()); // mbserver
}
}
음, 사실은 구성 요소 가 초기 화 될 때 현재 구성 요 소 를 JMX 에 등록 하 는 것 입 니 다. 구체 적 인 Tomcat 의 JMX 부분 내용 은 앞의 글 에서 이미 말 했 습 니 다. 여 기 는 자세히 말 하지 않 겠 습 니 다.
즉, 하나의 유형 이 JMX 에 등록 해 야 한다 면 LifeCycleMBeanBase 추상 류 를 계승 한 다음 에 그 중의 몇 가지 추상 적 인 방법 을 실현 해 야 한 다 는 것 이다.
자, 여기까지. 라 이 프 사이클 부분의 내용 은 많 지 않 습 니 다.
전체적인 느낌 으로 Tomcat 의 라 이 프 사이클 부분 디자인 은 비교적 간단 한 편 인 데...
자, 이제 서버 부분 내용 을 살 펴 보 겠 습 니 다...우선 최상 위 인터페이스의 정 의 를 살 펴 보 자.
package org.apache.catalina;
import java.io.File;
import org.apache.catalina.deploy.NamingResourcesImpl;
import org.apache.catalina.startup.Catalina;
// server ,
public interface Server extends Lifecycle {
// ------------------------------------------------------------- Properties
/**
* Return the global naming resources.
*/
public NamingResourcesImpl getGlobalNamingResources();
/**
* Set the global naming resources.
*
* @param globalNamingResources The new global naming resources
*/
public void setGlobalNamingResources
(NamingResourcesImpl globalNamingResources);
/**
* Return the global naming resources context.
*/
public javax.naming.Context getGlobalNamingContext();
/**
* Return the port number we listen to for shutdown commands.
*/
public int getPort(); // shutdown
/**
* Set the port number we listen to for shutdown commands.
*
* @param port The new port number
*/
public void setPort(int port); //// shutdown
/**
* Return the address on which we listen to for shutdown commands.
*/
public String getAddress(); // shutdown
/**
* Set the address on which we listen to for shutdown commands.
*
* @param address The new address
*/
public void setAddress(String address); // shutdown
/**
* Return the shutdown command string we are waiting for.
*/
public String getShutdown();
/**
* Set the shutdown command we are waiting for.
*
* @param shutdown The new shutdown command
*/
public void setShutdown(String shutdown);
public ClassLoader getParentClassLoader(); // server classLoader, catalina loader
public void setParentClassLoader(ClassLoader parent);
public Catalina getCatalina(); // catalina
public void setCatalina(Catalina catalina); // catalina
public File getCatalinaBase(); // tomcat
public void setCatalinaBase(File catalinaBase);
public File getCatalinaHome();
public void setCatalinaHome(File catalinaHome);
public void addService(Service service); // service
public void await();
public Service findService(String name); // service
public Service[] findServices(); // service
public void removeService(Service service); // service
}
음, 사실 최상 위 서버 인터페이스의 정의 도 간단 합 니 다. lifecycle 인터페이스 에서 가장 중요 한 부분 은 service 에 대한 추가 와 제거 가 아 닙 니 다.
가장 큰 소 리 를 지 르 는 것 은 바로 그것 이 service 용기 라 는 것 이다.
자, 다음은 가장 많이 사용 되 는 유형 인 StandardServer 를 살 펴 보 겠 습 니 다. 여기 에는 Server 인터페이스 뿐만 아니 라 LifecycleMBeanBase 유형 도 계승 되 었 습 니 다. 여기 에는 StandardServer 가 JMX 에 등 록 될 것 임 을 나타 냅 니 다.
그것 의 코드 가 비교적 길 기 때문에, 여 기 는 직접 붙 이지 않 는 다.비교적 중요 한 속성 정 의 를 내 립 시다:
private Service services[] = new Service[0]; // service,
private final Object servicesLock = new Object();
응, service 의 배열...응, 용 기 잖 아...
자, 여기 서도 초기 화 와 시동 두 가지 방법의 실현 을 살짝 살 펴 보 자.
protected void initInternal() throws LifecycleException {
super.initInternal(); // init, mbserver
// Register global String cache
// Note although the cache is global, if there are multiple Servers
// present in the JVM (may happen when embedding) then the same cache
// will be registered under multiple names
onameStringCache = register(new StringCache(), "type=StringCache");
// Register the MBeanFactory
MBeanFactory factory = new MBeanFactory(); // MBeanFactory
factory.setContainer(this); // mbeanfactory container
onameMBeanFactory = register(factory, "type=MBeanFactory"); // mbeanfactory
// Register the naming resources
globalNamingResources.init(); //
// Populate the extension validator with JARs from common and shared
// class loaders
if (getCatalina() != null) { // catalina
ClassLoader cl = getCatalina().getParentClassLoader(); // bootstrap shareloader
// Walk the class loader hierarchy. Stop at the system class loader.
// This will add the shared (if present) and common class loaders
// classLoader , classLoader
while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
if (cl instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) cl).getURLs();
for (URL url : urls) {
if (url.getProtocol().equals("file")) {
try {
File f = new File (url.toURI());
if (f.isFile() &&
f.getName().endsWith(".jar")) {
ExtensionValidator.addSystemResource(f);
}
} catch (URISyntaxException e) {
// Ignore
} catch (IOException e) {
// Ignore
}
}
}
}
cl = cl.getParent();
}
}
// Initialize our defined Services
for (int i = 0; i < services.length; i++) { // service
services[i].init();
}
}
우선 초기 화 입 니 다. 여기 서 가장 중요 한 것 은 현재 포 함 된 모든 서 비 스 를 초기 화 하 는 것 입 니 다. 그리고 다른 조작 도 있 습 니 다. 주석 도 설명 하 는 것 이 비교적 명확 한 것 이 라 고 할 수 있 습 니 다.
// lifecycle start , , tomcat, server service
@Override
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
globalNamingResources.start();
// Start our defined Services
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) { // service,
services[i].start();
}
}
}
시작 방법, 여기 서 가장 중요 한 것 도 역시 Service 에 대한 시작 입 니 다...
자, 여기까지. 서버 의 대체적인 물건 은 여기까지 입 니 다. 사실은 건어물 이 많 지 않 습 니 다.
일 을 가장 많이 하 는 곳 은 커 넥 터 부분 에 있 을 텐 데 이 건 나중에 쓰 자...
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.