LifecycleMBeanBase被许多类继承,本文浅析之(由分析知——jmx是tomcat的基础)
LifecycleMBeanBase继承了LifecycleBase,实现了jmxEnabled,内部依赖org.apache.tomcat.util.modeler.Registry
分别用于生命周期的管理(start,init,stop,destroy),以及jmx——java拓展管理
1 生命周期
All Implemented Interfaces:
MBeanRegistration, JmxEnabled, Lifecycle
Direct Known Subclasses:
Connector, ContainerBase, FailedContext, ManagerBase, MapperListener, NamingResourcesImpl, RealmBase, SimpleTcpCluster, StandardRoot,StandardServer, StandardService, StandardThreadExecutor, ValveBase, WebappLoader
Lifecycle:
主要实现start stop init destroy方法,并留有startInternal,stopInternal等方法给子类实现
/**
* Common interface for component life cycle methods. Catalina components
* may implement this interface (as well as the appropriate interface(s) for
* the functionality they support) in order to provide a consistent mechanism
* to start and stop the component.
* <br>
* The valid state transitions for components that support {@link Lifecycle}
* are:
* <pre>
* start()
* -----------------------------
* | |
* | init() |
* NEW -»-- INITIALIZING |
* | | | | ------------------«-----------------------
* | | |auto | | |
* | | \|/ start() \|/ \|/ auto auto stop() |
* | | INITIALIZED --»-- STARTING_PREP --»- STARTING --»- STARTED --»--- |
* | | | | |
* | |destroy()| | |
* | --»-----«-- ------------------------«-------------------------------- ^
* | | | |
* | | \|/ auto auto start() |
* | | STOPPING_PREP ----»---- STOPPING ------»----- STOPPED -----»-----
* | \|/ ^ | ^
* | | stop() | | |
* | | -------------------------- | |
* | | | | |
* | | | destroy() destroy() | |
* | | FAILED ----»------ DESTROYING ---«----------------- |
* | | ^ | |
* | | destroy() | |auto |
* | --------»----------------- \|/ |
* | DESTROYED |
* | |
* | stop() |
* ----»-----------------------------»------------------------------
*
* Any state can transition to FAILED.
*
* Calling start() while a component is in states STARTING_PREP, STARTING or
* STARTED has no effect.
*
* Calling start() while a component is in state NEW will cause init() to be
* called immediately after the start() method is entered.
*
* Calling stop() while a component is in states STOPPING_PREP, STOPPING or
* STOPPED has no effect.
*
* Calling stop() while a component is in state NEW transitions the component
* to STOPPED. This is typically encountered when a component fails to start and
* does not start all its sub-components. When the component is stopped, it will
* try to stop all sub-components - even those it didn't start.
*
* Attempting any other transition will throw {@link LifecycleException}.
*
* </pre>
* The {@link LifecycleEvent}s fired during state changes are defined in the
* methods that trigger the changed. No {@link LifecycleEvent}s are fired if the
* attempted transition is not valid.
*
* @author Craig R. McClanahan
*/
public interface Lifecycle {
// ----------------------------------------------------- Manifest Constants
/**
* The LifecycleEvent type for the "component before init" event.
*/
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";
/**
* The LifecycleEvent type for the "configure_start" event. Used by those
* components that use a separate component to perform configuration and
* need to signal when configuration should be performed - usually after
* {@link #BEFORE_START_EVENT} and before {@link #START_EVENT}.
*/
public static final String CONFIGURE_START_EVENT = "configure_start";
/**
* The LifecycleEvent type for the "configure_stop" event. Used by those
* components that use a separate component to perform configuration and
* need to signal when de-configuration should be performed - usually after
* {@link #STOP_EVENT} and before {@link #AFTER_STOP_EVENT}.
*/
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.
*
* @return An array containing 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);
/**
* Prepare the component for starting. This method should perform any
* initialization required post object creation. The following
* {@link LifecycleEvent}s will be fired in the following order:
* <ol>
* <li>INIT_EVENT: On the successful completion of component
* initialization.</li>
* </ol>
*
* @exception LifecycleException if this component detects a fatal error
* that prevents this component from being used
*/
public void init() throws LifecycleException;
/**
* Prepare for the beginning of active use of the public methods other than
* property getters/setters and life cycle methods of this component. This
* method should be called before any of the public methods other than
* property getters/setters and life cycle methods of this component are
* utilized. The following {@link LifecycleEvent}s will be fired in the
* following order:
* <ol>
* <li>BEFORE_START_EVENT: At the beginning of the method. It is as this
* point the state transitions to
* {@link LifecycleState#STARTING_PREP}.</li>
* <li>START_EVENT: During the method once it is safe to call start() for
* any child components. It is at this point that the
* state transitions to {@link LifecycleState#STARTING}
* and that the public methods other than property
* getters/setters and life cycle methods may be
* used.</li>
* <li>AFTER_START_EVENT: At the end of the method, immediately before it
* returns. It is at this point that the state
* transitions to {@link LifecycleState#STARTED}.
* </li>
* </ol>
*
* @exception LifecycleException if this component detects a fatal error
* that prevents this component from being used
*/
public void start() throws LifecycleException;
/**
* Gracefully terminate the active use of the public methods other than
* property getters/setters and life cycle methods of this component. Once
* the STOP_EVENT is fired, the public methods other than property
* getters/setters and life cycle methods should not be used. The following
* {@link LifecycleEvent}s will be fired in the following order:
* <ol>
* <li>BEFORE_STOP_EVENT: At the beginning of the method. It is at this
* point that the state transitions to
* {@link LifecycleState#STOPPING_PREP}.</li>
* <li>STOP_EVENT: During the method once it is safe to call stop() for
* any child components. It is at this point that the
* state transitions to {@link LifecycleState#STOPPING}
* and that the public methods other than property
* getters/setters and life cycle methods may no longer be
* used.</li>
* <li>AFTER_STOP_EVENT: At the end of the method, immediately before it
* returns. It is at this point that the state
* transitions to {@link LifecycleState#STOPPED}.
* </li>
* </ol>
*
* Note that if transitioning from {@link LifecycleState#FAILED} then the
* three events above will be fired but the component will transition
* directly from {@link LifecycleState#FAILED} to
* {@link LifecycleState#STOPPING}, bypassing
* {@link LifecycleState#STOPPING_PREP}
*
* @exception LifecycleException if this component detects a fatal error
* that needs to be reported
*/
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. The format of this string may vary between point releases and
* should not be relied upon to determine component state. To determine
* component state, use {@link #getState()}.
*
* @return The name of the current component state.
*/
public String getStateName();
/**
* Marker interface used to indicate that the instance should only be used
* once. Calling {@link #stop()} on an instance that supports this interface
* will automatically call {@link #destroy()} after {@link #stop()}
* completes.
*/
public interface SingleUse {
}
}
主要定义事件的转态,事件的注册、注销等
lifeCycleBase
/**
* Base implementation of the {@link Lifecycle} interface that implements the
* state transition rules for {@link Lifecycle#start()} and
* {@link Lifecycle#stop()}
*/
public abstract class LifecycleBase implements Lifecycle {
private static final Log log = LogFactory.getLog(LifecycleBase.class);
private static final StringManager sm = StringManager.getManager(LifecycleBase.class);
/**
* The list of registered LifecycleListeners for event notifications.
*/
private final List<LifecycleListener> lifecycleListeners = new CopyOnWriteArrayList<>();
/**
* The current state of the source component.
*/
private volatile LifecycleState state = LifecycleState.NEW;
private boolean throwOnFailure = true;
......
}
其中用到了LifecycleListener和LlifeCycleState
/**
* Interface defining a listener for significant events (including "component
* start" and "component stop" generated by a component that implements the
* Lifecycle interface. The listener will be fired after the associated state
* change has taken place.
*
* @author Craig R. McClanahan
*/
public interface LifecycleListener {
/**
* Acknowledge the occurrence of the specified event.
*
* @param event LifecycleEvent that has occurred
*/
public void lifecycleEvent(LifecycleEvent event);
}
/**
* The list of valid states for components that implement {@link Lifecycle}.
* See {@link Lifecycle} for the state transition diagram.
*/
public enum LifecycleState {
NEW(false, null),
INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT),
INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT),
STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT),
STARTING(true, Lifecycle.START_EVENT),
STARTED(true, Lifecycle.AFTER_START_EVENT),
STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT),
STOPPING(false, Lifecycle.STOP_EVENT),
STOPPED(false, Lifecycle.AFTER_STOP_EVENT),
DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT),
DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT),
FAILED(false, null);
private final boolean available;
private final String lifecycleEvent;
private LifecycleState(boolean available, String lifecycleEvent) {
this.available = available;
this.lifecycleEvent = lifecycleEvent;
}
/**
* May the public methods other than property getters/setters and lifecycle
* methods be called for a component in this state? It returns
* <code>true</code> for any component in any of the following states:
* <ul>
* <li>{@link #STARTING}</li>
* <li>{@link #STARTED}</li>
* <li>{@link #STOPPING_PREP}</li>
* </ul>
*
* @return <code>true</code> if the component is available for use,
* otherwise <code>false</code>
*/
public boolean isAvailable() {
return available;
}
public String getLifecycleEvent() {
return lifecycleEvent;
}
}
/**
* General event for notifying listeners of significant changes on a component
* that implements the Lifecycle interface.
*
* @author Craig R. McClanahan
*/
public final class LifecycleEvent extends EventObject {
private static final long serialVersionUID = 1L;
/**
* 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;
}
/**
* The event data associated with this event.
*/
private final Object data;
/**
* The event type this instance represents.
*/
private final String type;
/**
* @return the event data of this event.
*/
public Object getData() {
return 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;
}
}
/**
* <p>
* The root class from which all event state objects shall be derived.
* <p>
* All Events are constructed with a reference to the object, the "source",
* that is logically deemed to be the object upon which the Event in question
* initially occurred upon.
*
* @since JDK1.1
*/
public class EventObject implements java.io.Serializable {
private static final long serialVersionUID = 5516075349620653480L;
/**
* The object on which the Event initially occurred.
*/
protected transient Object source;
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @exception IllegalArgumentException if source is null.
*/
public EventObject(Object source) {
if (source == null)
throw new IllegalArgumentException("null source");
this.source = source;
}
/**
* The object on which the Event initially occurred.
*
* @return The object on which the Event initially occurred.
*/
public Object getSource() {
return source;
}
/**
* Returns a String representation of this EventObject.
*
* @return A a String representation of this EventObject.
*/
public String toString() {
return getClass().getName() + "[source=" + source + "]";
}
}
注意LifecycleBase的lifecycleListeners是copyOnWriteList
@Override public final synchronized void init() throws LifecycleException { if (!state.equals(LifecycleState.NEW)) { invalidTransition(Lifecycle.BEFORE_INIT_EVENT); } try { setStateInternal(LifecycleState.INITIALIZING, null, false); initInternal(); setStateInternal(LifecycleState.INITIALIZED, null, false); } catch (Throwable t) { handleSubClassException(t, "lifecycleBase.initFail", toString()); } }
init方法是个同步方法,如果state的状态不是new,会抛出LifecycleException异常
private void invalidTransition(String type) throws LifecycleException { String msg = sm.getString("lifecycleBase.invalidTransition", type, toString(), state); throw new LifecycleException(msg); }
init方法调用initInternal(),是个抽象方法,留给子类实现
init方法两次调用setStateInternal方法,这也是同步方法,由于执行init的调用者已经获得当前对象的锁,所以会调用这个方法,而不阻塞(主要作用是触发监听其事件的监听器)
private synchronized void setStateInternal(LifecycleState state, Object data, boolean check) throws LifecycleException { if (log.isDebugEnabled()) { log.debug(sm.getString("lifecycleBase.setState", this, state)); } if (check) { // Must have been triggered by one of the abstract methods (assume // code in this class is correct) // null is never a valid state if (state == null) { invalidTransition("null"); // Unreachable code - here to stop eclipse complaining about // a possible NPE further down the method return; } // Any method can transition to failed // startInternal() permits STARTING_PREP to STARTING // stopInternal() permits STOPPING_PREP to STOPPING and FAILED to // STOPPING if (!(state == LifecycleState.FAILED || (this.state == LifecycleState.STARTING_PREP && state == LifecycleState.STARTING) || (this.state == LifecycleState.STOPPING_PREP && state == LifecycleState.STOPPING) || (this.state == LifecycleState.FAILED && state == LifecycleState.STOPPING))) { // No other transition permitted invalidTransition(state.name()); } } this.state = state; String lifecycleEvent = state.getLifecycleEvent(); if (lifecycleEvent != null) { fireLifecycleEvent(lifecycleEvent, data); } }
/** * Allow sub classes to fire {@link Lifecycle} events. * * @param type Event type * @param data Data associated with event. */ protected void fireLifecycleEvent(String type, Object data) { LifecycleEvent event = new LifecycleEvent(this, type, data); for (LifecycleListener listener : lifecycleListeners) { listener.lifecycleEvent(event); } }
这种处理异常的方式值得学习
private void handleSubClassException(Throwable t, String key, Object... args) throws LifecycleException { ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); String msg = sm.getString(key, args); if (getThrowOnFailure()) { if (!(t instanceof LifecycleException)) { t = new LifecycleException(msg, t); } throw (LifecycleException) t; } else { log.error(msg, t); } }
这是start方法
/** * {@inheritDoc} */ @Override public final synchronized void start() throws LifecycleException { if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) || LifecycleState.STARTED.equals(state)) { //如果正在启动中,则打印日志,return if (log.isDebugEnabled()) { Exception e = new LifecycleException(); log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e); } else if (log.isInfoEnabled()) { log.info(sm.getString("lifecycleBase.alreadyStarted", toString())); } return; } if (state.equals(LifecycleState.NEW)) { init();//如果状态是new,执行初始化 } else if (state.equals(LifecycleState.FAILED)) { stop();//如果状态是failed,执行stop } else if (!state.equals(LifecycleState.INITIALIZED) && !state.equals(LifecycleState.STOPPED)) {//如果已经初始化,或停止,抛异常 invalidTransition(Lifecycle.BEFORE_START_EVENT); } try { setStateInternal(LifecycleState.STARTING_PREP, null, false);//设置全局state startInternal(); if (state.equals(LifecycleState.FAILED)) { // This is a 'controlled' failure. The component put itself into the // FAILED state so call stop() to complete the clean-up. stop(); } else if (!state.equals(LifecycleState.STARTING)) { // Shouldn't be necessary but acts as a check that sub-classes are // doing what they are supposed to. invalidTransition(Lifecycle.AFTER_START_EVENT); } else { setStateInternal(LifecycleState.STARTED, null, false); } } catch (Throwable t) { // This is an 'uncontrolled' failure so put the component into the // FAILED state and throw an exception. handleSubClassException(t, "lifecycleBase.startFail", toString()); } }
该方法会根据state值决定调用init,stop方法,以下是stop方法
/** * {@inheritDoc} */ @Override public final synchronized void stop() throws LifecycleException { if (LifecycleState.STOPPING_PREP.equals(state) || LifecycleState.STOPPING.equals(state) || LifecycleState.STOPPED.equals(state)) {//如果将、正在、已经stop if (log.isDebugEnabled()) { Exception e = new LifecycleException(); log.debug(sm.getString("lifecycleBase.alreadyStopped", toString()), e); } else if (log.isInfoEnabled()) { log.info(sm.getString("lifecycleBase.alreadyStopped", toString())); } return; } if (state.equals(LifecycleState.NEW)) { state = LifecycleState.STOPPED; return; } if (!state.equals(LifecycleState.STARTED) && !state.equals(LifecycleState.FAILED)) { invalidTransition(Lifecycle.BEFORE_STOP_EVENT); } try { if (state.equals(LifecycleState.FAILED)) { // Don't transition to STOPPING_PREP as that would briefly mark the // component as available but do ensure the BEFORE_STOP_EVENT is // fired fireLifecycleEvent(BEFORE_STOP_EVENT, null); } else { setStateInternal(LifecycleState.STOPPING_PREP, null, false); } stopInternal(); // Shouldn't be necessary but acts as a check that sub-classes are // doing what they are supposed to. if (!state.equals(LifecycleState.STOPPING) && !state.equals(LifecycleState.FAILED)) { invalidTransition(Lifecycle.AFTER_STOP_EVENT); } setStateInternal(LifecycleState.STOPPED, null, false); } catch (Throwable t) { handleSubClassException(t, "lifecycleBase.stopFail", toString()); } finally { if (this instanceof Lifecycle.SingleUse) { // Complete stop process first setStateInternal(LifecycleState.STOPPED, null, false); destroy(); } } }
如果其实现了Lifecycle.SingleUse接口,会调用destroy方法(有一点疑问,在destroy()方法里也会调用stop()方法,会有问题吗)
@Override public final synchronized void destroy() throws LifecycleException { if (LifecycleState.FAILED.equals(state)) { try { // Triggers clean-up stop(); } catch (LifecycleException e) { // Just log. Still want to destroy. log.warn(sm.getString( "lifecycleBase.destroyStopFail", toString()), e); } } if (LifecycleState.DESTROYING.equals(state) || LifecycleState.DESTROYED.equals(state)) { if (log.isDebugEnabled()) { Exception e = new LifecycleException(); log.debug(sm.getString("lifecycleBase.alreadyDestroyed", toString()), e); } else if (log.isInfoEnabled() && !(this instanceof Lifecycle.SingleUse)) { // Rather than have every component that might need to call // destroy() check for SingleUse, don't log an info message if // multiple calls are made to destroy() log.info(sm.getString("lifecycleBase.alreadyDestroyed", toString())); } return; } if (!state.equals(LifecycleState.STOPPED) && !state.equals(LifecycleState.FAILED) && !state.equals(LifecycleState.NEW) && !state.equals(LifecycleState.INITIALIZED)) { invalidTransition(Lifecycle.BEFORE_DESTROY_EVENT); }//只有 停止ed,失败ed,初始化ed,new 可以destroy,pre ing不可以 try { setStateInternal(LifecycleState.DESTROYING, null, false); destroyInternal(); setStateInternal(LifecycleState.DESTROYED, null, false); } catch (Throwable t) { handleSubClassException(t, "lifecycleBase.destroyFail", toString()); } }
2 jmx
/**
* This interface is implemented by components that will be registered with an
* MBean server when they are created and unregistered when they are destroyed.
* It is primarily intended to be implemented by components that implement
* {@link Lifecycle} but is not exclusively for them.
*/
public interface JmxEnabled extends MBeanRegistration {
/**
* @return the domain under which this component will be / has been
* registered.
*/
String getDomain();
/**
* Specify the domain under which this component should be registered. Used
* with components that cannot (easily) navigate the component hierarchy to
* determine the correct domain to use.
*
* @param domain The name of the domain under which this component should be
* registered
*/
void setDomain(String domain);
/**
* @return the name under which this component has been registered with JMX.
*/
ObjectName getObjectName();
}
/**
* <p>Can be implemented by an MBean in order to
* carry out operations before and after being registered or unregistered from
* the MBean Server. An MBean can also implement this interface in order
* to get a reference to the MBean Server and/or its name within that
* MBean Server.</p>
* 用于在mbean的注册前后、注销前后做相关操作
* @since 1.5
*/
public interface MBeanRegistration {
/**
* Allows the MBean to perform any operations it needs before
* being registered in the MBean Server. If the name of the MBean
* is not specified, the MBean can provide a name for its
* registration. If any exception is raised, the MBean will not be
* registered in the MBean Server.
*
* @param server The MBean Server in which the MBean will be registered.
*
* @param name The object name of the MBean. This name is null if
* the name parameter to one of the <code>createMBean</code> or
* <code>registerMBean</code> methods in the {@link MBeanServer}
* interface is null. In that case, this method must return a
* non-null ObjectName for the new MBean.
*
* @return The name under which the MBean is to be registered.
* This value must not be null. If the <code>name</code>
* parameter is not null, it will usually but not necessarily be
* the returned value.
*
* @exception java.lang.Exception This exception will be caught by
* the MBean Server and re-thrown as an {@link
* MBeanRegistrationException}.
*/
public ObjectName preRegister(MBeanServer server,
ObjectName name) throws java.lang.Exception;
/**
* Allows the MBean to perform any operations needed after having been
* registered in the MBean server or after the registration has failed.
* <p>If the implementation of this method throws a {@link RuntimeException}
* or an {@link Error}, the MBean Server will rethrow those inside
* a {@link RuntimeMBeanException} or {@link RuntimeErrorException},
* respectively. However, throwing an exception in {@code postRegister}
* will not change the state of the MBean:
* if the MBean was already registered ({@code registrationDone} is
* {@code true}), the MBean will remain registered. </p>
* <p>This might be confusing for the code calling {@code createMBean()}
* or {@code registerMBean()}, as such code might assume that MBean
* registration has failed when such an exception is raised.
* Therefore it is recommended that implementations of
* {@code postRegister} do not throw Runtime Exceptions or Errors if it
* can be avoided.</p>
* @param registrationDone Indicates whether or not the MBean has
* been successfully registered in the MBean server. The value
* false means that the registration phase has failed.
*/
public void postRegister(Boolean registrationDone);
/**
* Allows the MBean to perform any operations it needs before
* being unregistered by the MBean server.
*
* @exception java.lang.Exception This exception will be caught by
* the MBean server and re-thrown as an {@link
* MBeanRegistrationException}.
*/
public void preDeregister() throws java.lang.Exception ;
/**
* Allows the MBean to perform any operations needed after having been
* unregistered in the MBean server.
* <p>If the implementation of this method throws a {@link RuntimeException}
* or an {@link Error}, the MBean Server will rethrow those inside
* a {@link RuntimeMBeanException} or {@link RuntimeErrorException},
* respectively. However, throwing an exception in {@code postDeregister}
* will not change the state of the MBean:
* the MBean was already successfully deregistered and will remain so. </p>
* <p>This might be confusing for the code calling
* {@code unregisterMBean()}, as it might assume that MBean deregistration
* has failed. Therefore it is recommended that implementations of
* {@code postDeregister} do not throw Runtime Exceptions or Errors if it
* can be avoided.</p>
*/
public void postDeregister();
}
3 Registry
注册表,用于创建、操作mbean,并简化其使用,其自身也是一个mbean。以下是其全局变量
/*
Issues:
- exceptions - too many "throws Exception"
- double check the interfaces
- start removing the use of the experimental methods in tomcat, then remove
the methods ( before 1.1 final )
- is the security enough to prevent Registry beeing used to avoid the permission
checks in the mbean server ?
*/
/**
* Registry for modeler MBeans.
*
* This is the main entry point into modeler. It provides methods to create
* and manipulate model mbeans and simplify their use.
*
* This class is itself an mbean.
*
* IMPORTANT: public methods not marked with @since x.x are experimental or
* internal. Should not be used.
*
* @author Craig R. McClanahan
* @author Costin Manolache
*/
public class Registry implements RegistryMBean, MBeanRegistration {
/**
* The Log instance to which we will write our log messages.
*/
private static final Log log = LogFactory.getLog(Registry.class);
// Support for the factory methods
/** Will be used to isolate different apps and enhance security.
* 隔离app并增强其安全性:key用来隔离,Registry.guard确保安全性
*/
private static final HashMap<Object,Registry> perLoaderRegistries = null;
/**
* The registry instance created by our factory method the first time
* it is called.所有注册表实例对应一个默认注册表
*/
private static Registry registry = null;
// Per registy fields
/**
* The <code>MBeanServer</code> instance that we will use to register
* management beans. 所有注册表有自己的MBeanServer
*/
private MBeanServer server = null;
/**
* The set of ManagedBean instances for the beans this registry
* knows about, keyed by name.
*/
private HashMap<String,ManagedBean> descriptors = new HashMap<>();
/** List of managed beans, keyed by class name
*/
private HashMap<String,ManagedBean> descriptorsByClass = new HashMap<>();
// map to avoid duplicated searching or loading descriptors
private HashMap<String,URL> searchedPaths = new HashMap<>();
private Object guard;//守护者,用于阻止不信任的组件
// Id - small ints to use array access. No reset on stop()
// Used for notifications
private final Hashtable<String,Hashtable<String,Integer>> idDomains =
new Hashtable<>();
private final Hashtable<String,int[]> ids = new Hashtable<>();
getRegistry 获取注册表,静态同步方法,线程安全
/**
* Factory method to create (if necessary) and return our
* <code>Registry</code> instance.
*
* The current version uses a static - future versions could use
* the thread class loader.
*
* @param key Support for application isolation. If null, the context class
* loader will be used ( if setUseContextClassLoader is called ) or the
* default registry is returned. key用于app隔离
* @param guard Prevent access to the registry by untrusted components 用于阻止不信任的组件访问注册表
* @return the registry
* @since 1.1
*/
public static synchronized Registry getRegistry(Object key, Object guard) {
Registry localRegistry;
if( perLoaderRegistries!=null ) {
if( key==null )
key=Thread.currentThread().getContextClassLoader();//获取当前线程的classLoader
if( key != null ) {
localRegistry = perLoaderRegistries.get(key);
if( localRegistry == null ) {
localRegistry=new Registry();
// localRegistry.key=key;
localRegistry.guard=guard;
perLoaderRegistries.put( key, localRegistry );
return localRegistry;
}
if( localRegistry.guard != null &&
localRegistry.guard != guard ) {//验证守护者
return null; // XXX Should I throw a permission ex ?
}
return localRegistry;
}
}
// static
if (registry == null) {//registry是静态的(单例)
registry = new Registry();
}
if( registry.guard != null &&
registry.guard != guard ) {
return null;
}
return (registry);
}
getMBeanServer 实例、同步方法 获取MBeanServer,可以看出,每个registry的MBeanServer是单例、延时加载的
/**
* Factory method to create (if necessary) and return our
* <code>MBeanServer</code> instance.
* @return the MBean server
*/
public synchronized MBeanServer getMBeanServer() {
if (server == null) {
long t1 = System.currentTimeMillis();
if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
server = MBeanServerFactory.findMBeanServer(null).get(0);
if (log.isDebugEnabled()) {
log.debug("Using existing MBeanServer " + (System.currentTimeMillis() - t1));
}
} else {
server = ManagementFactory.getPlatformMBeanServer();
if (log.isDebugEnabled()) {
log.debug("Creating MBeanServer" + (System.currentTimeMillis() - t1));
}
}
}
return server;
}
下面方法根据给定的bean、objectName,动态生成DynamicMBean,并注册到MBeanServer
/**
* Register a component
* 注册组件(jmx)
* @param bean The bean
* @param oname The object name
* @param type The registry type
* @throws Exception Error registering component
*/
public void registerComponent(Object bean, ObjectName oname, String type)
throws Exception
{
if( log.isDebugEnabled() ) {
log.debug( "Managed= "+ oname);
}
if( bean ==null ) {
log.error("Null component " + oname );
return;
}
try {
if( type==null ) {//当type传null时,type=bean的类名
type=bean.getClass().getName();
}
ManagedBean managed = findManagedBean(null, bean.getClass(), type);
// The real mbean is created and registered
DynamicMBean mbean = managed.createMBean(bean);
if( getMBeanServer().isRegistered( oname )) {
if( log.isDebugEnabled()) {
log.debug("Unregistering existing component " + oname );
}
getMBeanServer().unregisterMBean( oname );
}
getMBeanServer().registerMBean( mbean, oname);
} catch( Exception ex) {
log.error("Error registering " + oname, ex );
throw ex;
}
}
4 LifecycleMBeanBase
以下是全局变量,jmx部分可参考 https://my.oschina.net/u/1380557/blog/797972
private static final Log log = LogFactory.getLog(LifecycleMBeanBase.class);//日志
private static final StringManager sm =
StringManager.getManager("org.apache.catalina.util");//日志信息
/* Cache components of the MBean registration. */
private String domain = null;//jmx domain
private ObjectName oname = null;// jmx objectName
protected MBeanServer mserver = null;//jmx MBeanServer
这是initInternal方法,init方法/start方法会调用。作用是初始化MBeanServer,将当前对象转成MBean并注册到MBeanServer中。获取mserver的方法在上面,重点看register方法
/**
* Sub-classes wishing to perform additional initialization should override
* this method, ensuring that super.initInternal() is the first call in the
* overriding method.
* 子类复写本方法时,需将super.initInternal()放第一行。与jmx的注册初始化相关
*/
@Override
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();
oname = register(this, getObjectNameKeyProperties());
}
}
/**
* Utility method to enable sub-classes to easily register additional
* components that don't implement {@link JmxEnabled} with an MBean server.
* 方便子类注册组件到MBean server而不用实现JmxEabled
* <br>
* Note: This method should only be used once {@link #initInternal()} has
* been called and before {@link #destroyInternal()} has been called.
*
* @param obj The object the register 要注册的对象
* @param objectNameKeyProperties The key properties component of the objectName要用
* object name to use to register the
* object
*
* @return The name used to register the object
*/
protected final ObjectName register(Object obj,
String objectNameKeyProperties) {
// Construct an object name with the right domain
StringBuilder name = new StringBuilder(getDomain());
name.append(':');
name.append(objectNameKeyProperties);
ObjectName on = null;
try {
on = new ObjectName(name.toString());
//根据给定的bean与ObjectName, 生成DynamicMBean, 并注册到MBeanServer
Registry.getRegistry(null, null).registerComponent(obj, on, null);
} catch (MalformedObjectNameException e) {
log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name),
e);
} catch (Exception e) {
log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name),
e);
}
return on;
}
/**
* Obtain the domain under which this component will be / has been
* registered.
*/
@Override
public final String getDomain() {
if (domain == null) {
domain = getDomainInternal();
}
if (domain == null) {
domain = Globals.DEFAULT_MBEAN_DOMAIN;
}
return domain;
}
/**
* Method implemented by sub-classes to identify the domain in which MBeans
* should be registered.
*
* @return The name of the domain to use to register MBeans.
*/
protected abstract String getDomainInternal();
这是destroyInternal方法
/**
* 子类复写此方法时,在方法的最后 super.destroyInternal()
* Sub-classes wishing to perform additional clean-up should override this
* method, ensuring that super.destroyInternal() is the last call in the
* overriding method.
*/
@Override
protected void destroyInternal() throws LifecycleException {
unregister(oname);
}
/**
* Utility method to enable sub-classes to easily unregister additional
* components that don't implement {@link JmxEnabled} with an MBean server.
* <br>
* Note: This method should only be used once {@link #initInternal()} has
* been called and before {@link #destroyInternal()} has been called.
*
* @param on The name of the component to unregister
*/
protected final void unregister(ObjectName on) {
// If null ObjectName, just return without complaint
if (on == null) {
return;
}
// If the MBeanServer is null, log a warning & return
if (mserver == null) {
log.warn(sm.getString("lifecycleMBeanBase.unregisterNoServer", on));
return;
}
try {
mserver.unregisterMBean(on);
} catch (MBeanRegistrationException e) {
log.warn(sm.getString("lifecycleMBeanBase.unregisterFail", on), e);
} catch (InstanceNotFoundException e) {
log.warn(sm.getString("lifecycleMBeanBase.unregisterFail", on), e);
}
}
这是MBeanRegistration接口方法的实现,可以指定MBeanServer, objectName, (因为在初始化时,都会先判空)
/** * Allows the object to be registered with an alternative * {@link MBeanServer} and/or {@link ObjectName}. */ @Override public final ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { this.mserver = server; this.oname = name; this.domain = name.getDomain(); return oname; }