次のように、インターネットからWebプロジェクトのディレクトリ構造を見つけました。
おなじみのラッシュではないですか^-^
数年前、これは当然の主流でしたが、テクノロジーの開発により、servlet3.0とspringbootが誕生し、xml構成に基づくWebプロジェクトは永久になくなり、springbootに置き換えられました。今日は、springbootの再生方法については説明しません。今日のトピックは、web.xmlがどのように消えるかです。現在の主流のテクノロジーはSpringFamily Bucketであるため、調査の目的は、Springがweb.xmlをどのように消滅させるかということでもあります。springmvcのコアはDispacherServletです。これを使用すると、<servlet>タグがweb.xmlで構成されます。次に、web.xmlが消えると、DispacherServletはどのようにコンテナに登録されますか?この問題を解決することで、web.xmlが消えた理由にも答えることができます。
Servlet3.0
servlet3.0以降、ServletContainerInitializerインターフェースをサポートします。つまり、サーブレット、リスナー、フィルターの登録など、コードレベルでサーブレットコンテナーを初期化する方法を提供します。公式ドキュメントでのServletContainerInitializerの紹介は次のとおりです。
ServletContainerInitializerクラスは、jarサービスAPIを介して検出されます。アプリケーションごとに、アプリケーションの起動時に、ServletContainerInitializerインスタンスがコンテナーによって作成されます。フレームワークによって提供されるServletContainerInitializer実装は、jarパッケージのMETA-INF / servicesディレクトリにあるjavax.servlet.ServletContainerInitializerというファイルにバインドする必要があります。jarサービスAPIに従って、ServletContainerInitializerの実装を指定します。ServletContainerInitializerに加えて、HandlesTypesという注釈もあります。ServletContainerInitializer実装のHandlesTypesアノテーションは、対象となるいくつかのクラスを示すために使用されます。HandlesTypesの値にアノテーション(タイプ、メソッド、または自動レベルアノテーション)を指定するか、そのタイプのスーパークラスがこれらのクラスを継承/実装します。
簡単に言えば、ServletContainerInitializerの実装クラスがjar内の特定のディレクトリファイルで構成されている限り、サーブレットコンテナは起動プロセス中にこの実装クラスを呼び出して、サーブレット、リスナー、およびフィルタを登録する機能を実現します。次にweb.xmlの有用性を完全に置き換えることができます。
春のウェブパッケージ
Springに精通している人は、Webアプリケーションを開発するときにspring-webパッケージが不可欠であることを知っている必要があります。このパッケージのディレクトリ構造を見てみましょう。
嬉しい驚きでしたか?servlet3.0の場合、SpringはそのServletContainerInitializerの特性をサポートします。これを見ると、結論が出ています。Springはこの方法でサーブレット登録をサポートしています。SpringServletContainerInitializerがどのように実装されているかを見てみましょう。ソースコード
//1
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
//2
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
//3
initializer.onStartup(servletContext);
}
}
}
// 1コレクションwebAppInitializerClassesとして@HandlesTypesアノテーションを介して、対象のクラス(WebApplicationInitializerとそのサブクラス)を取得します
onStartupメソッドに渡されます
// 2webAppInitializerClassesコレクションの実装クラスを除外します
// 3 WebApplicationInitializerの実装クラスをトラバースし、onStartupメソッドを呼び出します
WebApplicationInitializerの実装クラス
図に示すように、赤いボックス内の抽象クラスは、DispatcherServletの登録を実現するのに特に役立ちます。また、おなじみの授業を見ましたね。はい、それはSpringBootServletInitializerであり、それに精通しており、すべてを急いで返す必要はありません。Springbootを起動するために外部Webコンテナを使用する必要がある場合は、前のコンテナに基づいてアプリケーションを変更する必要があります。そのうちの1つは、SpringBootServletInitializerを継承することです。ここでは説明しません。興味がある場合は、学習できます。自分でフォローします。スプリングブーツ関連の記事もフォローします。、詳細を知りたい友達はフォローしてください^-^
さて、これらの3つの抽象クラスを見てみましょう
onStartupメソッドが心配です。onStartupの実装はAbstractDispatcherServletInitializerで説明されています。
最初に親クラスAbstractContextLoaderInitializerのonStartupメソッドを呼び出し、次にDispatcherServletを登録します。
AbstractContextLoaderInitializerのonStartupメソッド
最初のステップは、AbstractDispatcherServletInitializerに実装されたルートコンテナー(親コンテナー)を作成することです。
AnnotationConfigWebApplicationContextを作成し、@ Configurationアノテーション付きクラスを登録します。これには通常、サービス、dao(リポジトリ)、Beanが含まれます。
2. ContextLoaderListenerを作成し、サーブレットコンテナに登録します。サーブレットコンテナが起動したら、ルートコンテナを更新します。
DispatcherServletを登録する
最初のステップであるcreateServletApplicationContext()は、AbstractAnnotationConfigDispatcherServletInitializerにも実装されています。これは、実際にはAnnotationConfigWebApplicationContextであり、サブコンテナーとしてDispatcherServletにバインドされています。
AnnotationConfigWebApplicationContextインスタンスを初期化し、@ Configurationアノテーション付きクラス(通常はコントローラー)を登録し、ViewRoverやInterceptorなどのspringmvc関連のBeanもサブコンテナーに格納されます。
2番目のステップは、DispatcherServletを作成し、子コンテナーを属性としてDispatcherServletにバインドすることです。
3番目のステップは、サーブレットコンテナにDispatcherServletを追加し、サーブレットマッピングパスloadOnstartup orderを設定することです。これにより、サーブレットコンテナが開始されると、DispatcherServletのinitメソッドが呼び出されます。これは、主に実装されているinitServletBeanメソッドを呼び出します。 FrameworkServletのコード上
initWebApplicationContextメソッドを見てください
最初にルートコンテナを取得し、次にルートコンテナを単語コンテナの親として設定し(ここでは親コンテナと単語コンテナのソースも確認します)、最後に単語コンテナを更新します(springiocに精通している友人は十分に注意する必要があります) spirngコンテナの更新の重要性)
この時点で、WebApplicationInitializerの下に継承された3つのクラスが導入されましたが、正しいですか?突然、春がこのように再生されていることがわかりました。実はまだ終わっていません。SpringServletContainerInitializerがonStartupメソッドの実行時に関心のあるWebApplicationInitailizerクラスとそのサブクラスを渡し、インターフェイスと抽象クラスを削除すると最初に言ったときのことを今でも覚えています。先ほど紹介したのはすべて抽象クラスです。私の衝動?シャオアンは落ち着きがない。以前も混乱していましたが、なぜ実装クラスを提供しなかったのですか?私はspringbootプロジェクトに取り組んでいるので、この問題を隠します。実際、sprigbootは、DispatcherServletをサーブレットコンテナに登録するためにこのルートをまったく使用しません。ここでは、springbootの再生方法については触れません。springbootを使用せず、この方法でサーブレットを登録したい場合はどうすればよいですか。非常に単純で、実装クラスはなく、作成するだけです。非常に単純ですか?私は長い間混乱してきました(555)。コードをアップロード
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class AnnotationConfigDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{ServletConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/*"};
}
}
@Configuration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.ANNOTATION, classes = {Controller.class})})
class RootConfig {
}
@Configuration
@ComponentScan(useDefaultFilters = false, includeFilters = {@Filter(type = FilterType.ANNOTATION, classes = {Controller.class})})
class ServletConfig
メインの論理抽象クラスはヘルプ用に実装されています。3つのメソッドを実装するだけで済みます。getRootConfigClassesはルートコンテナの作成に役立ち、getServletConfigClassesはサブコンテナの作成に役立ち、getServletMappingsはDispatcherServletのマッピングパスの構成に役立ちます。