まず、クラスローディング機構Java仮想マシンを見てください。
ブートストラップクラスローダ(読み込みJRE \ libに\ rt.jarのXbootclasspath指定されたJARまたはパケット用)
拡張クラスローダ(標準拡張ディレクトリをロードするための/ JDK / JRE / libに/ EXT)
(CLASSPATH環境変数またはDJava.class.path jarファイルとディレクトリをロードするための)システムクラスローダー
カスタムクラスローダ(ユーザ定義のクラスローダ)
両方の両親に準拠するクラスローダ委譲モデル、読み込みファイルが最初にその親ローダー負荷に委任されたときに、親ローダは成功、その後、ロードされています。親が負荷をダウンロードできない場合は、負荷へのサブローダーに委任されます。
Tomcatのサーブレットコンテナは、2つの理由のために、独自のクラスローダを定義します。
あなたはセキュリティ上の問題を解決することができるので、一方で我々は、それを止めることができますが、仮想マシンのクラスで別の実行をロードするために信頼することはできません。サーブレットコンテナが唯一のWEB-INF / classesディレクトリとそのサブディレクトリロードされたクラスの依存WEB-INF / libにヘッドをエンジニアリングすることができTOMCAT、このローダはインタフェースorg.apache.catalina.Loader.javaを実装する必要があります。
別の態様は、WEB-INF / classesまたはWEB-INF可能/変更は、Tomcatは、このようなローダ実装インタフェースorg.apache下の2つのファイルの変更を監視するスレッドを開始します場合は、以下のファイルが自動的にロードされlibに。 catalina.loader.Reloader.java。はい、あなたはクラスファイルを変更するローカルデバッグは、Tomcatを再起動することではありません
2つのソースファイルを次のように
パブリックインターフェイスローダ{
// -------------------------------------------- -----------------プロパティ
/ **
*などされるなど、この方法をリロードするよう、定期的なタスクを実行します
*このコンテナのクラスローディングコンテキスト内で呼び出されました。予期しない
*スロー可能オブジェクトがキャッチされ、ログに記録されます。
* /
パブリック無効のbackgroundProcess();
/ **
*このコンテナが使用するJavaクラスローダを返します。
* /
パブリッククラスローダのgetClassLoader();
/ **
*このLoaderは関連していたとのコンテナを返します。
* /
公共コンテナgetContainer();
/ **
*このLoaderは関連していたとのコンテナを設定します。
*
* @paramコンテナ関連コンテナ
* /
公共ボイドsetContainer(コンテナ容器)
/ **
*戻り設定するために使用される「標準委譲モデルに従う」フラグ
*私たちのクラスローダ。
* /
パブリックブールによりgetDelegate();
/ **
*構成するために使用される「標準委譲モデルに従う」フラグを設定し
、当社のクラスローダ*。
*
* @paramデリゲート新しいフラグ
* /
パブリック無効setDelegate(ブールデリゲート)。
/ **
このローダ実装と約*リターン記述情報
の形式で*対応のバージョン番号、
説明&GT; /&LT;バージョン&gt; </ code>の* <コード>&LT。
* /
パブリック文字列GETINFO();
/ **
*このローダーのリロードフラグを返します。
* /
getReloadableブールパブリック();
/ **
*このローダーのリロードフラグを設定します。
*
* @paramリロード新しいリロードフラグ
* /
パブリック無効setReloadable(ブールリロード可能)。
// ------------------------------------------------ ---------パブリックメソッド
/ **
*このコンポーネントにプロパティ変更リスナーを追加します。
*
追加する* @paramリスナーリスナー
* /
公共のボイドのaddPropertyChangeListener(PropertyChangeListenerをリスナー)。
/ **
*このクラスローダのためのリポジトリのセットに新しいリポジトリを追加します。
*
* @paramリポジトリリポジトリ追加する
* /
公共ボイドaddRepository(文字列リポジトリ)。
/ **
*このクラスローダのために定義されたリポジトリのセットを返します。
何も定義されていない場合*、長さゼロの配列が返されます。
* /
パブリック文字列[] findRepositories()。
/ **
*このローダーに関連する内部リポジトリは、変更されている
ロードされたクラスを再ロードしなければならない*ように?
* /
パブリックブール)(変性;
/ **
*このコンポーネントからプロパティ変更リスナーを削除します。
*
削除する* @paramリスナーリスナー
* /
パブリック無効removePropertyChangeListener(PropertyChangeListenerをリスナー)。
}
public interface Reloader {
/**
* Add a new repository to the set of places this ClassLoader can look for
* classes to be loaded.
*
* @param repository Name of a source of classes to be loaded, such as a
* directory pathname, a JAR file pathname, or a ZIP file pathname
*
* @exception IllegalArgumentException if the specified repository is
* invalid or does not exist
*/
public void addRepository(String repository);
/**
* Return a String array of the current repositories for this class
* loader. If there are no repositories, a zero-length array is
* returned.
*/
public String[] findRepositories();
/**
* Have one or more classes or resources been modified so that a reload
* is appropriate?
*/
public boolean modified();
}
tomcat类加载器的UML图如下
先来看看WebappLoader.java,它创建了一个WebappClassLoader的实例作为自己的类加载器。它实现了Loader.java接口,并且跟其他catalina组件一样,也实现了 org.apache.catalina.Lifecycle接口以便能被其他容器打开和关闭。同时也实现了java.beans.PropertyChangeListener接口,当属性改变时通知相关容器。而WebappLoader本身的重启是由Context(tomcat的容器)来控制的。
WebappLoader的启动的时候会发生下面几个工作:
如果没有初始化,则初始化并且注册容器;如果是第一次初始化,为JNDI注册流处理器;创建类加载器;设置repository;设置classpath;设置权限;为目录绑定类加载器。
public void start() throws LifecycleException {
// Validate and update our current component state
if( ! initialized ) init();
if (started)
throw new LifecycleException
(sm.getString("webappLoader.alreadyStarted"));
if (log.isDebugEnabled())
log.debug(sm.getString("webappLoader.starting"));
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
if (container.getResources() == null) {
log.info("No resources for " + container);
return;
}
// Register a stream handler factory for the JNDI protocol
URLStreamHandlerFactory streamHandlerFactory =
new DirContextURLStreamHandlerFactory();
if (first) {
first = false;
try {
URL.setURLStreamHandlerFactory(streamHandlerFactory);
} catch (Exception e) {
// Log and continue anyway, this is not critical
log.error("Error registering jndi stream handler", e);
} catch (Throwable t) {
// This is likely a dual registration
log.info("Dual registration of jndi stream handler: "
+ t.getMessage());
}
}
// Construct a class loader based on our current repositories list
try {
classLoader = createClassLoader();
classLoader.setResources(container.getResources());
classLoader.setDelegate(this.delegate);
if (container instanceof StandardContext)
classLoader.setAntiJARLocking(((StandardContext) container).getAntiJARLocking());
for (int i = 0; i < repositories.length; i++) {
classLoader.addRepository(repositories[i]);
}
// Configure our repositories
setRepositories();
setClassPath();
setPermissions();
if (classLoader instanceof Lifecycle)
((Lifecycle) classLoader).start();
// Binding the Webapp class loader to the directory context
DirContextURLStreamHandler.bind
((ClassLoader) classLoader, this.container.getResources());
StandardContext ctx=(StandardContext)container;
Engine eng=(Engine)ctx.getParent().getParent();
String path = ctx.getPath();
if (path.equals("")) {
path = "/";
}
ObjectName cloname = new ObjectName
(ctx.getEngineName() + ":type=WebappClassLoader,path="
+ path + ",host=" + ctx.getParent().getName());
Registry.getRegistry(null, null)
.registerComponent(classLoader, cloname, null);
} catch (Throwable t) {
log.error( "LifecycleException ", t );
throw new LifecycleException("start: ", t);
}
}