どのスプリング@RequestMapping処理(要求パス・コントローラ・クラスまたはメソッドをマッピングする方法)

アドレス重版:http://blog.csdn.net/j080624/article/details/56278461
記事の長さを短縮するため、記事では、より多くのゴール指向、簡単な技術になり、私たちは、このような@RequestMappingの使用状況などのさまざまなコンテンツを引用しません。
具体的な使用状況@RequestMapping表示します
記事は、以下の質問に固有のものです:

どのスプリング@RequestMapping処理(要求パス・コントローラ・クラスまたはメソッドをマッピングする方法)

スプリングどのディスパッチに正しいコントローラクラスまたはメソッドに要求

ばねリアライズ方法フレキシブル制御方法

在Spring MVC 3.1 之前的版本中,Spring默认使用 DefaultAnnotationHandlerMapping,AnnotationMethodHandlerAdapter来处理 @RequestMapping注解和请求方法调用,而从3.1开始提供了一组新的API完成这些工作。相比之下,新的API更加的合理完善,开放,易拓 展,面向对象。这篇文章便是基于3.1的新API进行剖析的。

まず、コンセプト決意
我々は新しいインターフェイスを理解し始める前には、背後にあるプロセスを理解するのに役立ちます新しいAPI、またはクラスを導入しました。新しいAPIは、より美しい抽象化を提供し、オブジェクト指向のあなたが魅力を感じることができることを言わなければなりません。

RequestMappingInfoこのクラスは、要求のパスを含む抽象マップリクエスト、リクエストメソッド、要求クラス情報です。実際には、対応するクラスの@RequestMappingとして見ることができます。

HandlerMethodプロセッサインスタンス(コントローラ豆)および実施例(方法)の処理方法をパッケージのこのタイプ、およびメソッドパラメータ配列(MethodParameter [])

情報及びそのようなパラメータのインデックス、例、インスタンスまたは構成の方法に関連するパラメータは、パラメータの種類として行動方法のパラメータをカプセル化し、そこからMethodParameterクラス2.0。

インタフェースは前の要求と唯一の方法getHandlerを定義し、プロセッサ間のマッピングを定義するために使用される実装するクラスをHandlerMapping。

AbstractHandlerMethodMapping HandlerMappingこれは基本的に要求HandlerMethodインスタンス間のマッピングを定義するクラスです。

このAbstractHandlerMethodMappingされる実装クラスをRequestMappingInfoHandlerMapping、彼はRequestMappingInfoとHandlerMethod地図のプロパティを保持します。

これは、RequestMappingInfo例に注釈を@RequestMapping、親クラスとして使用、RequestMappingInfoHandlerMapping RequestMappingHandlerMappingサブクラスです。これは、私たちが最後に@RequestMappingに対処するものです。

このインタフェースは、その実装は、コンテナのプロパティの完了後にカスタム初期化動作を行うことができる、我々はこのインタフェースを実装AbstractHandlerMethodMapping、およびカスタムアクションのセットを定義しますInitializingBeanビーンを定義し、当社のプロセスは、注釈を@RequestMapping検出するために使用されます。

概念讲的太多总不是什么好事。但明白了上述概念基本上就成功一半了,其中的实现相对@Autowired那篇简单多了。

二、InitialiZingBean.afterPropertySetは()
我々が最後に見て、ゼロからスタート、我々は注釈を@RequestMapping検出し、春に対処する方法です。我々はまだ気にしない、このコードを覚えているだろうか。

[Javaの]ビュープレインコピー
オブジェクトexposedObject =豆;
試し{
populateBean(のbeanName、MBD、instanceWrapper);
IFは(!exposedObject = NULL){
exposedObject = initializeBean(のbeanName、exposedObject、MBD);
}
}
これは、たBeanFactoryでは、ビーン・プロセスを作成しましたこの方法は、属性自動注射器の操作によって行わpopulateBean @Autowired注釈処理手順であることを特徴とコードの一部は、実行されます。当時のinitializeBean方法は、トピックとは何の関係も言ってませんでしたが、今回はそれが私たちの注目の的だからです。

上面概念中我们讲到InitiaizingBean接口,它的实现Bean会在容器完成属性注入后执行一个自定义操作,这不就满足initializeBean方法的执行唤醒嘛,我们来看它的实现:

[Javaの]プレインビューコピーは、
オブジェクトinitializeBean(最終文字列のbeanName、豆最終的なオブジェクト、RootBeanDefinition MBD){保護された
IF(System.getSecurityManagerの()!= NULL){
AccessController.doPrivilegedの(PrivilegedActionの新新(){
パブリックオブジェクトRUN(){
invokeAwareMethodsは、 (のbeanName、豆);
戻りNULL;
}
}、getAccessControlContext());
}
//ここ{他現在の行認識Beanは、いくつかのインターフェースを実装し、関連したメソッドを呼び出し、我々は気にしないかどうかを検出します。
invokeAwareMethods(のbeanName、豆);
}

    Object wrappedBean = bean;  
    if (mbd == null || !mbd.isSynthetic()) {//BeanPostProcessor 的回调,不关心  
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);  
    }  

    try {  
        invokeInitMethods(beanName, wrappedBean, mbd);//这是我们需要关心的,下面看下它的实现  
    }  

    if (mbd == null || !mbd.isSynthetic()) {//BeanPostProcessor 的回调,不关心  
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);  
    }  
    return wrappedBean;  
}  

私たちは、その後、実現invokeInitMethods方法を見てみましょう。

【ジャワ】無地コピー視聴
保護ボイドinvokeInitMethods(文字列のbeanName、最終的なオブジェクト豆、RootBeanDefinitionのMBD)
のThrowable {スロー
//是否是InitializingBean的实例
ブールisInitializingBean =(InitializingBean instanceofの豆)を、
(isInitializingBean &&場合
(MBD == nullの||!mbd.isExternallyManagedInitMethod(「afterPropertiesSet」))){
場合(System.getSecurityManager()!= NULL){
試み{
AccessController.doPrivilegedの(新たPrivilegedExceptionAction(){
パブリックオブジェクトの実行( )例外がスロー{//利用系统安全管理器调用
((InitializingBean)ビーン).afterPropertiesSetを();
戻りNULL;
}
}、getAccessControlContext())。
}
}
他に{//がafterPropertiesSet方法のInitializingBeanを呼び出します。
((InitializingBean)豆).afterPropertiesSet();
}
}
//カスタム初期化メソッドを呼び出します。省略、気にしない
}
についての記事にMVC:注釈駆動型/設定ファイル内のフラグと相まって記事、我々は言った、春(3.1)は、当社の登録RequestMappingHandlerMappingなどBean定義がデフォルトになります。そしてRequestMappingHandlerMappingは、上記のコードを実行するために、彼はafterPropertySet方法を実行するので、初期化中およびBeanインスタンスを当てはめること、InitializingBeanインタフェースを実現しました。私たちは、その後、彼のafterPropertySet方法を見てみましょう。

【ジャワ】プレーンコピー視聴
公共ボイドafterPropertiesSet(){
initHandlerMethodsを();
}

//Scan beans in the ApplicationContext, detect and register handler methods.  
protected void initHandlerMethods() {  
    //扫描所有注册的Bean  
    String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?  
       BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(),   
            Object.class) : getApplicationContext().getBeanNamesForType(Object.class));  
    //遍历这些Bean,依次判断是否是处理器,并检测其HandlerMethod  
    for (String beanName : beanNames) {  
        if (isHandler(getApplicationContext().getType(beanName))){  
            detectHandlerMethods(beanName);  
        }  
    }  
    //这个方法是个空实现,不管他  
    handlerMethodsInitialized(getHandlerMethods());  
}  

これは、直接initHandlerMethods()メソッドと呼ばれ、方法は以下のように記載されている:スキャンのApplicationContext豆、登録プロセッサは検出方法。私たちは近くにあります。

第三に、@RequestMapping検出
我々はそれを見ては、ハンドラメソッドのを検出する方法としてだけでなく、プロセッサかどうかを判断する方法です。

[Javaの]プレインビューコピー
@Overrideは
ブールisHandler(クラス<?> BeanType){保護された
リターン((AnnotationUtils.findAnnotation(BeanType、Controller.class)!= NULL)||
(AnnotationUtils.findAnnotation(BeanType、RequestMapping.classは)!ヌル=));
}
AHA、コメントタグ@Controllerまたは@RequestMappingがあるかどうかを確認することは非常に簡単です

【ジャワ】視聴無地コピー
保護されたボイドdetectHandlerMethods(最終オブジェクト・ハンドラ){
クラス<?> handlerType =(文字列のinstanceofハンドラ)?
getApplicationContext()のgetType((String)をハンドラ):。handler.getClass();
最終クラスUSERTYPE = ClassUtils.getUserClass(handlerType)<?>;
集合メソッド= HandlerMethodSelector.selectMethods(USERTYPE、新しいMethodFilter(){
パブリックブールマッチ(方法法){//只选择被@RequestMapping标记的方法
getMappingForMethod(メソッド、USERTYPE)を返す= NULL;!
}
})。

    for (Method method : methods) {  
        //根据方法上的@RequestMapping来创建RequestMappingInfo实例。  
        T mapping = getMappingForMethod(method, userType);  
        //注册请求映射  
        registerHandlerMethod(handler, method, mapping);  
    }  
}  

全体の検出プロセスは、実質的に透明である:1)メソッドハンドラの全てを通って、中の標識@RequestMappingアノテーション方法を見つけること。2)次にRequestMappingInfoインスタンスを生成する、これらの方法を横切ります。3)方法RequestMappingInfo例およびキャッシュ・プロセッサに登録。

下面我们看看细节:

[Javaの]プレインビューコピー
@Overrideは
RequestMappingInfo getMappingForMethod(<?>メソッド、メソッド、クラスhandlerType){保護
; RequestMappingInfo情報= NULL
//例@RequestMapping方法の方法を取得します。
MethodAnnotation = @RequestMapping
AnnotationUtils.findAnnotation(方法,, RequestMapping.class);
IF(!MethodAnnotation = NULL){//メソッドが注釈され
RequestCondition methodCondition = getCustomMethodConditionは(メソッド)は< ?>; // 常にnullを返します
情報= createRequestMappingInfo(methodAnnotationを、 methodCondition); //はMappingInfoを作成
//クラスのチェックが@RequestMappingコメント属し
@RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType、
RequestMapping.classを);
!IF(typeAnnotation = NULL){// @RequestMappingノートには、クラス階層を持っています
RequestCondition typeCondition = getCustomTypeCondition(handlerType)<?>; // nullが
// RequestMappingし、メソッドレベルのクラス階層を組み合わせるRequestMapping
情報= createRequestMappingInfo(typeAnnotation、typeCondition).combine(情報);
}
}
戻りインフォメーション;
}
非常にそれをオフ、まず方法に関する情報を取得し、@RequestMappingは、2つの組み合わせをクラスレベルでの情報を@RequestMapping取得、および、ここではRequestMappingInfoは(彼の内部構造を含む)の理解の下にオブジェクトを再作成する必要があるものを持っている、とどのようにクラス要求マッピング情報とメソッドレベルの組み合わせのレベル?

[javaの]はプレーンコピーを表示
プライベートRequestMappingInfo createRequestMappingInfo(RequestMapping注釈、
RequestCondition <?> customCondition){
リターン新しいRequestMappingInfo(
新PatternsRequestCondition(annotation.value()、getUrlPathHelper()、getPathMatcher()、
this.useSuffixPatternMatch、this.useTrailingSlashMatch、この.fileExtensions)、
新しいRequestMethodsRequestCondition(annotation.method())、
新しいParamsRequestCondition(annotation.params())、
新しいHeadersRequestCondition(annotation.headers())、
新しいConsumesRequestCondition(annotation.consumes()、annotation.headers())、
新しいProducesRequestCondition(annotation.produces()、annotation.headers()、
getContentNegotiationManager())、
customCondition
);
}
いくつかのクラスを伴う、我々は一般的な意味を理解します:

PatternRequestConditionそれは実際にURLパターンセットコレクションが含まれているパッケージのURLパターンです。実際には、値は、パッケージの価値のノートを@RequestMapping。

これは、RequestMethodRequestCondition注釈メソッド属性@RequestMappingパッケージ化されています

それはParamsRequestCondition @RequestMappingプロパティ注釈のparamsをパッケージ化されています

等等,依次类推。因此RequestMappingInfo其实就是对@RquestMapping 的封装。

下面我们再看看怎样进行Combine的:

[ジャワ]プレーンコピービュー
(RequestMappingInfo他){組み合わせるRequestMappingInfo公開
PatternsRequestConditionパターン= this.patternsCondition.combine(other.patternsCondition)。
RequestMethodsRequestConditionメソッド= this.methodsCondition.combine(other.methodsCondition)。
ParamsRequestConditionのparams = this.paramsCondition.combine(other.paramsCondition)。
HeadersRequestConditionヘッダー= this.headersCondition.combine(other.headersCondition)。
ConsumesRequestCondition消費= this.consumesCondition.combine(other.consumesCondition)。
ProducesRequestConditionは= this.producesCondition.combine(other.producesCondition)を生成します。
RequestConditionHolderカスタム= this.customConditionHolder.combine(other.customConditionHolder)。

return new RequestMappingInfo(patterns, methods, params, headers, consumes,   
                produces, custom.getCondition());  

} オペレーションを組み合わせた、私たちはここを見て、各要素のために、非常に明確であることは、URLをマージする方法を見てすることがいかにPatternRequestConditionの組み合わせ、です。他にはあまり必要ではありません。

【ジャワ】プレーンコピー視聴
公共PatternsRequestConditionは(PatternsRequestCondition他){組み合わせる
結果セット=新しいLinkedHashSetのを();
(もし!this.patterns.isEmpty()&& other.patterns.isEmpty()!){
(文字列のパターン1:this.patterns)のために、{
のための(文字列のパターン2:other.patterns){
result.add(this.pathMatcher.combine (パターン1、パターン2))。
}
}
}
そうであれば(this.patterns.isEmpty()!){
result.addAll(this.patterns)。
}
それ以外の場合(other.patterns.isEmpty()!){
result.addAll(other.patterns)。
}
{他
( "")result.add。
}
、新しいPatternsRequestCondition(その結果、this.urlPathHelper、this.pathMatcherを返します
this.useSuffixPatternMatch、this.useTrailingSlashMatch、this.fileExtensions);
}
。1)は、2つのパターンがあるは、二つのパターンをマージする方法を組み合わせるPathMatcherを呼び出すことです。

2)只有一个有时,使用这个。

3)两个都没有时,为空“”。

现在真正的url拼接是由PathMatcher来完成的了。我们就不看他的代码了就是一串if else的组合,重点是考虑进各种情况,我们来看下方法的注释吧:



清晰,全面吧,有兴趣的可以看一下代码,这里不讲了。

第四には、登録要求をマップする
春は確かに私たちの要求に対処するために、一緒にこの情報を保存する必要がありますことを、@RequestMappingに応じて、我々は発見と治療を@RequestMapping上記について話していること、およびRequestMappingInfoの例を生成します。

第三节中我们提到一个方法还没有分析,就是registerHandlerMethod 方法:

[ジャワ]ビュープレーンコピー
ボイドregisterHandlerMethod(オブジェクトハンドラ、メソッド、メソッド、Tマッピング){保護
HandlerMethod HandlerMethod;
IF(文字列のinstanceofハンドラ){
文字列のbeanName =(文字列)ハンドラ;
HandlerMethod =新しい新しいHandlerMethod(のbeanName、getApplicationContext()メソッド);
}
他{
HandlerMethod =新しい新しいHandlerMethod(ハンドラ、メソッド);
}
//上記の行新しいプロセッサHandlerMethodインスタンスの新しいインスタンスを生成することで、例示的な方法は、RequestMappingInfo
本がある場合、//以下は、キャッシュから見ましたHandlerMethod例、等しく存在しない場合とスロー
HandlerMethod oldHandlerMethod = handlerMethods.get(マッピング);
IF(oldHandlerMethod = NULL && oldHandlerMethod.equals(HandlerMethod)!!){
スロー新しい新しいIllegalStateExceptionを();
}
// handlerMethodsマップは、インスタンスの値がRequestMappingInfoオブジェクトは結合されHandlerMethodで
のみ処理方法のマッピング例による、マッピングHandlerMethod例の複数を処理する//ことが可能
this.handlerMethods.put(マッピング、HandlerMethod);
//ここでは、すべてのURLマッピングのインスタンスを取得します。
パターンgetMappingPathPatterns = SET(マッピング);
(文字列パターン:パターン)は{
IF(!。GetPathMatcher()isPattern(パターン)){
// URLMapも地図、キーURLモードであり、値はRequestMappingInfoインスタンスである
//したがって、マッピングの一例ですこれは、複数のパターンに対応するが、マッピング例に対応するパターンのみできる
this.urlMap.add(パターン、マッピング);
}
}
}

リクエストが一致urlMapのURL、マッピングを検索し、対応するインスタンスを取得し、取得したhandlerMethods HandlerMethodインスタンスに一致するようにする必要があるため、到着したとき、それは、非常に簡単です実際には、少し周りがあるかもしれません。

第五に、接続の間のリンク
いくつかの長いの長さ、単語限界を超えると、2つだけに...

这章只分析了我们前面三个问题中的第一个,但是已经相当接近了。下一篇我们来讲,Spring怎样处理客户发来的请求,以及方法调用的。

カテゴリー:JAVA

公開された37元の記事 ウォンの賞賛8 ビュー5295

おすすめ

転載: blog.csdn.net/weixin_42714605/article/details/99620553