Анализ запуска Tomcat 7 (5) Механизм жизненного цикла и принцип реализации

Java задняя часть исходный код Tomcat

существуетВ прошлой статье были проанализированы методы инициализации и запуска каждого компонента Tomcat 7.Я часто вижу вызов метода setStateInternal.Просматривая исходный код класса LifecycleBase и других компонентов, я во многих местах увижу вызов этого метода.В этой статье будет рассказано об этом методе и связанных с ним методах. Механизм жизненного цикла Tomcat и принцип реализации.

Продолжая вышесказанное, мы говорили о классе LifecycleBase, родительском классе каждого компонента Tomcat 7, который реализует интерфейс org.apache.catalina.Lifecycle, Ниже приведены константы и методы, определенные в этом интерфейсе:

Внимательные читатели обнаружат, что методы init и start, упомянутые в предыдущей статье, на самом деле определены в этом интерфейсе, и именно потому, что все компоненты в конечном итоге будут реализовывать этот интерфейс в качестве обязательного условия, чтобы они могли поддерживать initInternal внутри компонента. вызывается метод startInternal, методы init и start подкомпонентов (вложенные подкомпоненты в компоненте определены в виде интерфейсов, но эти интерфейсы будут использовать Lifecycle в качестве родительского интерфейса). Таким образом, пока вызываются методы init и start самого внешнего компонента сервера, все подкомпоненты в Tomcat могут быть инициализированы и запущены. Я называю этот способ цепными вызовами. На самом деле, механизм выключения Tomcat также вызывает метод остановки каждого уровня компонентов пошагово таким образом. Дальнейшее повествование здесь не приводится, и читателю предоставляется возможность самому исследовать и изучать.

Эти константные определения строки в интерфейсе жизненного цикла в основном используются для определения типов событий. Сначала нажмите таблицу, которая будет упомянуто позже в статье.

Сосредоточьтесь на следующих трех методах:


    /**
     * 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);//删除该组件中的一个监听器

Функции этих трех методов кратко объясняются в комментариях к коду. Эти три метода включают интерфейс org.apache.catalina.LifecycleListener, затем посмотрите определение этого интерфейса:


public interface LifecycleListener {


    /**
     * Acknowledge the occurrence of the specified event.
     *
     * @param event LifecycleEvent that has occurred
     */
    public void lifecycleEvent(LifecycleEvent event);


}

Так просто, есть только один метод, этот метод используется для уведомления класса реализации текущего слушателя, когда происходит событие ( org.apache.catalina.LifecycleEvent ), и класс реализации слушателя решает, как обрабатывать событие.

Взгляните на реализацию LifecycleEvent:


public final class LifecycleEvent extends EventObject {

    private static final long serialVersionUID = 1L;


    // ----------------------------------------------------------- Constructors

    /**
     * Construct a new LifecycleEvent with the specified parameters.
     *
     * @param lifecycle Component on which this event occurred
     * @param type Event type (required)
     * @param data Event data (if any)
     */
    public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {

        super(lifecycle);
        this.type = type;
        this.data = data;
    }


    // ----------------------------------------------------- Instance Variables


    /**
     * The event data associated with this event.
     */
    private Object data = null;


    /**
     * The event type this instance represents.
     */
    private String type = null;


    // ------------------------------------------------------------- Properties


    /**
     * Return the event data of this event.
     */
    public Object getData() {

        return (this.data);

    }


    /**
     * Return the Lifecycle on which this event occurred.
     */
    public Lifecycle getLifecycle() {

        return (Lifecycle) getSource();

    }


    /**
     * Return the event type of this event.
     */
    public String getType() {

        return (this.type);

    }


}

Этот класс также очень прост.Данные и тип используются как встроенные переменные экземпляра класса.Единственное, что нужно сделать, это использовать встроенный в jdk java.util.EventObject в качестве родительского класса для поддержки определения события.Здесь, org. apache.catalina Жизненный цикл экземпляра класса Lifecycle служит источником событий, сохраняет ссылку на объект жизненного цикла и предоставляет метод getLifecycle для возврата этой ссылки.

Так как же мониторинг и уведомление об этих событиях реализованы в Tomcat?

Строка 47 класса LifecycleBase, упомянутого в начале этой статьи, определяет переменную экземпляра lifecycle, которая используется для регистрации различных прослушивателей, определенных для компонента. Обратите внимание на жизненный цикл переменной экземпляра, который является не экземпляром класса org.apache.catalina.Lifecycle, а экземпляром класса org.apache.catalina.util.LifecycleSupport. Именно этот класс инструментов предоставляет функции мониторинга событий и уведомления о событиях.

Давайте сначала посмотрим, как уведомить время выпуска компонента в реальном коде, и посмотрим на метод startInternal класса org.apache.catalina.core.StandardServer, упомянутый в предыдущей статье:


     1	    protected void startInternal() throws LifecycleException {
     2	
     3	        fireLifecycleEvent(CONFIGURE_START_EVENT, null);
     4	        setState(LifecycleState.STARTING);
     5	
     6	        globalNamingResources.start();
     7	        
     8	        // Start our defined Services
     9	        synchronized (services) {
    10	            for (int i = 0; i < services.length; i++) {
    11	                services[i].start();
    12	            }
    13	        }
    14	    }

Мы уже проанализировали строки с 9 по 13 кода, вот строка 3, которая вызывает метод fireLifecycleEvent в родительском классе org.apache.catalina.util.LifecycleBase, гдеCONFIGURE_START_EVENTЭто константа, определенная в интерфейсе жизненного цикла в начале этой статьи, что означает, что публикуется событие конфигурации запуска.

Метод fireLifecycleEvent в классе org.apache.catalina.util.LifecycleBase вызывает метод fireLifecycleEvent класса org.apache.catalina.util.LifecycleSupport Код этого метода выглядит следующим образом:


    public void fireLifecycleEvent(String type, Object data) {

        LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
        LifecycleListener interested[] = listeners;
        for (int i = 0; i < interested.length; i++)
            interested[i].lifecycleEvent(event);

    }

Создайте объект LifecycleEvent, передав два параметра, а затем опубликуйте только что созданный объект события для всех слушателей, зарегистрированных в компоненте.

Вот вопрос, когда вы регистрируете слушатель в сборке?

Принимая стандарты в качестве примера, когда говорится о использовании Diagester ранее, метод CreatestArtdiGester методом org.apache.catalina.startup.catalina класса имеет такой кусок кода:


     1	        // Configure the actions we will be using
     2	        digester.addObjectCreate("Server",
     3	                                 "org.apache.catalina.core.StandardServer",
     4	                                 "className");
     5	        digester.addSetProperties("Server");
     6	        digester.addSetNext("Server",
     7	                            "setServer",
     8	                            "org.apache.catalina.Server");
     9	
    10	        digester.addObjectCreate("Server/GlobalNamingResources",
    11	                                 "org.apache.catalina.deploy.NamingResources");
    12	        digester.addSetProperties("Server/GlobalNamingResources");
    13	        digester.addSetNext("Server/GlobalNamingResources",
    14	                            "setGlobalNamingResources",
    15	                            "org.apache.catalina.deploy.NamingResources");
    16	
    17	        digester.addObjectCreate("Server/Listener",
    18	                                 null, // MUST be specified in the element
    19	                                 "className");
    20	        digester.addSetProperties("Server/Listener");
    21	        digester.addSetNext("Server/Listener",
    22	                            "addLifecycleListener",
    23	                            "org.apache.catalina.LifecycleListener");

Строки с 17 по 24 вызывают метод addLifecycleListener класса org.apache.catalina.core.StandardServer, создают экземпляр объекта в соответствии с атрибутом className, определенным узлом Listener в узле Server, настроенном в server.xml, и используют его как метод addLifecycleListener Введите ссылку. Все слушатели будут реализовывать упомянутый выше интерфейс org.apache.catalina.LifecycleListener. В узле сервера есть несколько узлов прослушивателя, вот пример org.apache.catalina.core.JasperListener.

После построения объекта класса org.apache.catalina.core.JasperListener вызовите метод addLifecycleListener, который не определен напрямую в классе org.apache.catalina.core.StandardServer, а в его родительском классе org.apache In . catalina.util.LifecycleBase:


    @Override
    public void addLifecycleListener(LifecycleListener listener) {
        lifecycle.addLifecycleListener(listener);
    }

Здесь вызывается метод addLifecycleListener вышеупомянутого класса org.apache.catalina.util.LifecycleSupport:


    /**
     * Add a lifecycle event listener to this component.
     *
     * @param listener The listener to add
     */
    public void addLifecycleListener(LifecycleListener listener) {

      synchronized (listenersLock) {
          LifecycleListener results[] =
            new LifecycleListener[listeners.length + 1];
          for (int i = 0; i < listeners.length; i++)
              results[i] = listeners[i];
          results[listeners.length] = listener;
          listeners = results;
      }

    }

В качестве класса инструмента LifecycleSupport внутренне сохраняет массив экземпляров объекта прослушивателя, см. строку 68 этого класса:


/** 
 * The set of registered LifecycleListeners for event notifications. 
 */  
private LifecycleListener listeners[] = new LifecycleListener[0];  

Внутренняя реализация вышеуказанного метода addLifecycleListener заключается в синхронном добавлении объекта прослушивателя в массив.

Увидев это, вы должны иметь общее представление о том, что происходит с жизненным циклом в Tomcat.В общем, это через класс инструментов LifecycleSupport, который вызывает метод addLifecycleListener этого класса для добавления прослушивателей.Когда вам нужно опубликовать события, вы все равно вызовите метод fireLifecycleEvent класса инструмента, опубликуйте событие для всех слушателей, зарегистрированных в компоненте, и внутренняя реализация слушателя решит, следует ли обрабатывать событие.

Возьмем, к примеру, прослушиватель org.apache.catalina.core.JasperListener, который мы видели ранее:


     1	public class JasperListener
     2	    implements LifecycleListener {
     3	
     4	    private static final Log log = LogFactory.getLog(JasperListener.class);
     5	
     6	    /**
     7	     * The string manager for this package.
     8	     */
     9	    protected static final StringManager sm =
    10	        StringManager.getManager(Constants.Package);
    11	
    12	
    13	    // ---------------------------------------------- LifecycleListener Methods
    14	
    15	
    16	    /**
    17	     * Primary entry point for startup and shutdown events.
    18	     *
    19	     * @param event The event that has occurred
    20	     */
    21	    @Override
    22	    public void lifecycleEvent(LifecycleEvent event) {
    23	
    24	        if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) {
    25	            try {
    26	                // Set JSP factory
    27	                Class.forName("org.apache.jasper.compiler.JspRuntimeContext",
    28	                              true,
    29	                              this.getClass().getClassLoader());
    30	            } catch (Throwable t) {
    31	                ExceptionUtils.handleThrowable(t);
    32	                // Should not occur, obviously
    33	                log.warn("Couldn't initialize Jasper", t);
    34	            }
    35	            // Another possibility is to do directly:
    36	            // JspFactory.setDefaultFactory(new JspFactoryImpl());
    37	        }
    38	
    39	    }
    40	
    41	
    42	}

Сосредоточьтесь на реализации метода lifecycleEvent из интерфейса.Вы можете видеть, что этот слушатель заботится только о типе события.BEFORE_INIT_EVENTЕсли событие опубликовано, будет выполнена последующая обработка (здесь будет сгенерирован объект org.apache.jasper.compiler.JspRuntimeContext).

UML-диаграмма классов, связанных с жизненным циклом:

Если вы знакомы с шаблонами проектирования, вы обнаружите, что жизненный цикл Tomcat использует шаблон наблюдателя: LifecycleListener представляет абстрактного наблюдателя, который определяет метод lifecycleEvent, а прослушиватель, реализующий этот интерфейс, действует как конкретный наблюдатель. Интерфейс жизненного цикла представляет собой абстрактный субъект, который определяет методы управления наблюдателями и другие методы, которые он делает. Каждый компонент представляет конкретную тему, которая реализует все методы абстрактной темы. Обычно конкретный субъект должен сохранять внутреннее состояние, полезное для конкретного объекта-наблюдателя; его наблюдатели уведомляются, когда это внутреннее состояние изменяется. Tomcat улучшил этот шаблон, добавив два других класса инструментов: LifecycleSupport и LifecycleEvent, которые расширяют функциональные возможности наблюдателей в качестве вспомогательных классов. Категории событий определяются в LifecycleEvent, и разные события могут обрабатываться по-разному в конкретных наблюдателях, что обеспечивает большую гибкость. Класс LifecycleSupport представляет для наблюдателя управление всеми конкретными темами, и это управление извлекается и реализуется единообразно. Если в будущем вы измените класс LifecycleSupport, вам потребуется изменить только класс LifecycleSupport. Вам не нужно изменять все определенные темы, так как все определенные темы работают с наблюдателем и делегируются классу LifecycleSupport.

Событие публикуется в режиме push, то есть каждый раз, когда событие публикуется, все конкретные наблюдатели темы будут уведомлены, и каждый наблюдатель затем будет решать, нужно ли событие обрабатывать позже.

Давайте взглянем на метод setStateInternal, упомянутый в начале этой статьи, взяв в качестве примера класс org.apache.catalina.core.StandardServer, четвертую строку в методе startInternal, показанном выше:setState(LifecycleState.STARTING);

Он вызывает метод setState в родительском классе org.apache.catalina.util.LifecycleBase:


    /**
     * Provides a mechanism for sub-classes to update the component state.
     * Calling this method will automatically fire any associated
     * {@link Lifecycle} event. It will also check that any attempted state
     * transition is valid for a sub-class.
     * 
     * @param state The new state for this component
     */
    protected synchronized void setState(LifecycleState state)
            throws LifecycleException {
        setStateInternal(state, null, true);
    }

В этом классе вызовите синхронный метод setStateInternal этого класса:


     1	    private synchronized void setStateInternal(LifecycleState state,
     2	            Object data, boolean check) throws LifecycleException {
     3	        
     4	        if (log.isDebugEnabled()) {
     5	            log.debug(sm.getString("lifecycleBase.setState", this, state));
     6	        }
     7	        
     8	        if (check) {
     9	            // Must have been triggered by one of the abstract methods (assume
    10	            // code in this class is correct)
    11	            // null is never a valid state
    12	            if (state == null) {
    13	                invalidTransition("null");
    14	                // Unreachable code - here to stop eclipse complaining about
    15	                // a possible NPE further down the method
    16	                return;
    17	            }
    18	            
    19	            // Any method can transition to failed
    20	            // startInternal() permits STARTING_PREP to STARTING
    21	            // stopInternal() permits STOPPING_PREP to STOPPING and FAILED to
    22	            // STOPPING
    23	            if (!(state == LifecycleState.FAILED ||
    24	                    (this.state == LifecycleState.STARTING_PREP &&
    25	                            state == LifecycleState.STARTING) ||
    26	                    (this.state == LifecycleState.STOPPING_PREP &&
    27	                            state == LifecycleState.STOPPING) ||
    28	                    (this.state == LifecycleState.FAILED &&
    29	                            state == LifecycleState.STOPPING))) {
    30	                // No other transition permitted
    31	                invalidTransition(state.name());
    32	            }
    33	        }
    34	        
    35	        this.state = state;
    36	        String lifecycleEvent = state.getLifecycleEvent();
    37	        if (lifecycleEvent != null) {
    38	            fireLifecycleEvent(lifecycleEvent, data);
    39	        }
    40	    }

Сосредоточьтесь на строках с 35 по 39. В строке 35 входной экземпляр LifecycleState назначается переменной экземпляра в этом классе и сохраняется. В строке 36 извлекается событие LifecycleEvent экземпляра LifecycleState. Если событие не пустое, вызовите метод fireLifecycleEvent, чтобы опубликовать мероприятие.

Теперь, когда вы видите класс LifecycleState, давайте взглянем на определение класса LifecycleState:


     1	public enum LifecycleState {
     2	    NEW(false, null),
     3	    INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT),
     4	    INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT),
     5	    STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT),
     6	    STARTING(true, Lifecycle.START_EVENT),
     7	    STARTED(true, Lifecycle.AFTER_START_EVENT),
     8	    STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT),
     9	    STOPPING(false, Lifecycle.STOP_EVENT),
    10	    STOPPED(false, Lifecycle.AFTER_STOP_EVENT),
    11	    DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT),
    12	    DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT),
    13	    FAILED(false, null),
    14	    MUST_STOP(true, null),
    15	    MUST_DESTROY(false, null);
    16	
    17	    private final boolean available;
    18	    private final String lifecycleEvent;
    19	
    20	    private LifecycleState(boolean available, String lifecycleEvent) {
    21	        this.available = available;
    22	        this.lifecycleEvent = lifecycleEvent;
    23	    }
    24	
    25	    /**
    26	     * May the public methods other than property getters/setters and lifecycle
    27	     * methods be called for a component in this state? It returns
    28	     * <code>true</code> for any component in any of the following states:
    29	     * <ul>
    30	     * <li>{@link #STARTING}</li>
    31	     * <li>{@link #STARTED}</li>
    32	     * <li>{@link #STOPPING_PREP}</li>
    33	     * <li>{@link #MUST_STOP}</li>
    34	     * </ul>
    35	     */
    36	    public boolean isAvailable() {
    37	        return available;
    38	    }
    39	
    40	    /**
    41	     *
    42	     */
    43	    public String getLifecycleEvent() {
    44	        return lifecycleEvent;
    45	    }
    46	}

Этот класс ранее не встречался в Tomcat 4 и Tomcat 5. Он может быть заново определен в Tomcat 7. Это перечисление с двумя встроенными переменными экземпляра, логическим значением, указывающим, доступен ли он, и строкой, указывающей, доступен ли он. или нет.Это тип события.Глядя на определенные значения перечисления, обнаруживается, что эта строка либо не установлена ​​в значение, либо является строковой константой, определенной в классе Lifecycle. Этот класс фактически является еще одним уровнем инкапсуляции для строковых констант, определенных в классе Lifecycle.

Возвращаясь к началу, вызов метода setStateInternal, который часто можно увидеть в коде каждого компонента, фактически публикует событие для зарегистрированного прослушивателя в компоненте.