Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
木_木_三
spring-framework
提交
8f558e7c
S
spring-framework
项目概览
木_木_三
/
spring-framework
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
spring-framework
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
8f558e7c
编写于
5月 03, 2015
作者:
R
Rossen Stoyanchev
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add methods to (un)register HandlerMethod mappings
Issue: SPR-11541
上级
6a28c86d
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
196 addition
and
79 deletion
+196
-79
spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java
...ork/web/servlet/handler/AbstractHandlerMethodMapping.java
+178
-74
spring-webmvc/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java
...mework/web/servlet/handler/HandlerMethodMappingTests.java
+18
-5
未找到文件。
spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java
浏览文件 @
8f558e7c
...
...
@@ -27,6 +27,7 @@ import java.util.List;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.locks.ReentrantReadWriteLock
;
import
javax.servlet.ServletException
;
import
javax.servlet.http.HttpServletRequest
;
...
...
@@ -89,7 +90,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
private
HandlerMethodMappingNamingStrategy
<
T
>
namingStrategy
;
private
final
Mapping
DefinitionRegistry
mappingRegistry
=
new
MappingDefinition
Registry
();
private
final
Mapping
Registry
mappingRegistry
=
new
Mapping
Registry
();
/**
...
...
@@ -123,10 +124,16 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
}
/**
* Return a
read-only map with all mappe
d HandlerMethod's.
* Return a
(read-only) map with all mappings an
d HandlerMethod's.
*/
public
Map
<
T
,
HandlerMethod
>
getHandlerMethods
()
{
return
this
.
mappingRegistry
.
getMappings
();
this
.
mappingRegistry
.
acquireReadLock
();
try
{
return
Collections
.
unmodifiableMap
(
this
.
mappingRegistry
.
getMappings
());
}
finally
{
this
.
mappingRegistry
.
releaseReadLock
();
}
}
/**
...
...
@@ -221,16 +228,27 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
/**
* Register a handler method and its unique mapping.
* <p>Invoked at startup for each detected handler method. May also be
* invoked at runtime after initialization is complete.
* @param handler the bean name of the handler or the handler instance
* @param method the method to register
* @param mapping the mapping conditions associated with the handler method
* @throws IllegalStateException if another method was already registered
* under the same mapping
*/
p
rotected
void
registerHandlerMethod
(
Object
handler
,
Method
method
,
T
mapping
)
{
p
ublic
void
registerHandlerMethod
(
Object
handler
,
Method
method
,
T
mapping
)
{
this
.
mappingRegistry
.
register
(
handler
,
method
,
mapping
);
}
/**
* Un-register a handler method.
* <p>This method may be invoked at runtime after initialization has completed.
* @param handlerMethod the handler method to be unregistered
*/
public
void
unregisterHandlerMethod
(
HandlerMethod
handlerMethod
)
{
this
.
mappingRegistry
.
unregister
(
handlerMethod
);
}
/**
* Create the HandlerMethod instance.
* @param handler either a bean name or an actual handler instance
...
...
@@ -279,16 +297,22 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
"Looking up handler method for path "
+
lookupPath
);
}
HandlerMethod
handlerMethod
=
lookupHandlerMethod
(
lookupPath
,
request
);
if
(
logger
.
isDebugEnabled
())
{
if
(
handlerMethod
!=
null
)
{
logger
.
debug
(
"Returning handler method ["
+
handlerMethod
+
"]"
);
}
else
{
logger
.
debug
(
"Did not find handler method for ["
+
lookupPath
+
"]"
);
this
.
mappingRegistry
.
acquireReadLock
();
try
{
HandlerMethod
handlerMethod
=
lookupHandlerMethod
(
lookupPath
,
request
);
if
(
logger
.
isDebugEnabled
())
{
if
(
handlerMethod
!=
null
)
{
logger
.
debug
(
"Returning handler method ["
+
handlerMethod
+
"]"
);
}
else
{
logger
.
debug
(
"Did not find handler method for ["
+
lookupPath
+
"]"
);
}
}
return
(
handlerMethod
!=
null
?
handlerMethod
.
createWithResolvedBean
()
:
null
);
}
finally
{
this
.
mappingRegistry
.
releaseReadLock
();
}
return
(
handlerMethod
!=
null
?
handlerMethod
.
createWithResolvedBean
()
:
null
);
}
/**
...
...
@@ -308,7 +332,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
}
if
(
matches
.
isEmpty
())
{
// No choice but to go through all mappings...
addMatchingMappings
(
this
.
mappingRegistry
.
getMapping
Keys
(),
matches
,
request
);
addMatchingMappings
(
this
.
mappingRegistry
.
getMapping
s
().
keySet
(),
matches
,
request
);
}
if
(!
matches
.
isEmpty
())
{
...
...
@@ -335,7 +359,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
return
bestMatch
.
handlerMethod
;
}
else
{
return
handleNoMatch
(
this
.
mappingRegistry
.
getMapping
Keys
(),
lookupPath
,
request
);
return
handleNoMatch
(
this
.
mappingRegistry
.
getMapping
s
().
keySet
(),
lookupPath
,
request
);
}
}
...
...
@@ -404,96 +428,126 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
}
private
class
MappingDefinitionRegistry
{
private
final
Map
<
Method
,
MappingDefinition
<
T
>>
mappingDefinitions
=
new
ConcurrentHashMap
<
Method
,
MappingDefinition
<
T
>>();
private
class
MappingRegistry
{
private
final
Map
<
T
,
HandlerMethod
>
mappingLookup
=
new
LinkedHashMap
<
T
,
HandlerMethod
>();
private
final
MultiValueMap
<
String
,
T
>
urlLookup
=
new
LinkedMultiValueMap
<
String
,
T
>();
private
final
Map
<
String
,
List
<
HandlerMethod
>>
n
ameLookup
=
private
final
Map
<
String
,
List
<
HandlerMethod
>>
mappingN
ameLookup
=
new
ConcurrentHashMap
<
String
,
List
<
HandlerMethod
>>();
private
final
Map
<
Method
,
MappingDefinition
<
T
>>
methodLookup
=
new
ConcurrentHashMap
<
Method
,
MappingDefinition
<
T
>>();
private
final
ReentrantReadWriteLock
readWriteLock
=
new
ReentrantReadWriteLock
();
/**
* Return a
read-only copy of all mappings
.
*
Safe for concurrent use.
* Return a
ll mappings and handler methods. Not thread-safe
.
*
@see #acquireReadLock()
*/
public
Map
<
T
,
HandlerMethod
>
getMappings
()
{
return
Collections
.
unmodifiableMap
(
this
.
mappingLookup
)
;
return
this
.
mappingLookup
;
}
/**
* Return matches for the given URL path. Not thread-safe.
* @see #acquireReadLock()
*/
public
List
<
T
>
getMappingKeysByUrl
(
String
urlPath
)
{
return
this
.
urlLookup
.
get
(
urlPath
);
}
public
Set
<
T
>
getMappingKeys
()
{
return
this
.
mappingLookup
.
keySet
();
}
/**
* Return the handler method for the mapping key. Not thread-safe.
* @see #acquireReadLock()
*/
public
HandlerMethod
getHandlerMethod
(
T
mapping
)
{
return
this
.
mappingLookup
.
get
(
mapping
);
}
/**
* Return HandlerMethod matches for the given mapping name.
* Safe for concurrent use.
* Return handler methods by mapping name. Thread-safe for concurrent use.
*/
public
List
<
HandlerMethod
>
getHandlerMethodsByMappingName
(
String
mappingName
)
{
return
this
.
n
ameLookup
.
get
(
mappingName
);
return
this
.
mappingN
ameLookup
.
get
(
mappingName
);
}
/**
* Return the CorsConfiguration for the given HandlerMethod, if any.
* Safe for concurrent use.
* Return CORS configuration. Thread-safe for concurrent use.
*/
public
CorsConfiguration
getCorsConfiguration
(
HandlerMethod
handlerMethod
)
{
Method
method
=
handlerMethod
.
getMethod
();
MappingDefinition
<
T
>
definition
=
this
.
m
appingDefinitions
.
get
(
method
);
MappingDefinition
<
T
>
definition
=
this
.
m
ethodLookup
.
get
(
method
);
return
(
definition
!=
null
?
definition
.
getCorsConfiguration
()
:
null
);
}
/**
* Acquire the read lock when using getMappings and getMappingKeysByUrl.
*/
public
void
acquireReadLock
()
{
this
.
readWriteLock
.
readLock
().
lock
();
}
/**
* Release the read lock after using getMappings and getMappingKeysByUrl.
*/
public
void
releaseReadLock
()
{
this
.
readWriteLock
.
readLock
().
unlock
();
}
public
void
register
(
Object
handler
,
Method
method
,
T
mapping
)
{
HandlerMethod
handlerMethod
=
createHandlerMethod
(
handler
,
method
);
assertUniqueMapping
(
handlerMethod
,
mapping
);
this
.
readWriteLock
.
writeLock
().
lock
();
try
{
HandlerMethod
handlerMethod
=
createHandlerMethod
(
handler
,
method
);
assertUniqueMethodMapping
(
handlerMethod
,
mapping
);
if
(
logger
.
isInfoEnabled
())
{
logger
.
info
(
"Mapped \""
+
mapping
+
"\" onto "
+
handlerMethod
);
}
this
.
mappingLookup
.
put
(
mapping
,
handlerMethod
);
if
(
logger
.
isInfoEnabled
())
{
logger
.
info
(
"Mapped \""
+
mapping
+
"\" onto "
+
handlerMethod
);
}
this
.
mappingLookup
.
put
(
mapping
,
handlerMethod
);
List
<
String
>
directUrls
=
extrac
tDirectUrls
(
mapping
);
for
(
String
url
:
directUrls
)
{
this
.
urlLookup
.
add
(
url
,
mapping
);
}
List
<
String
>
directUrls
=
ge
tDirectUrls
(
mapping
);
for
(
String
url
:
directUrls
)
{
this
.
urlLookup
.
add
(
url
,
mapping
);
}
String
name
=
null
;
if
(
getNamingStrategy
()
!=
null
)
{
name
=
getNamingStrategy
().
getName
(
handlerMethod
,
mapping
);
add
Name
(
name
,
handlerMethod
);
}
String
name
=
null
;
if
(
getNamingStrategy
()
!=
null
)
{
name
=
getNamingStrategy
().
getName
(
handlerMethod
,
mapping
);
addMapping
Name
(
name
,
handlerMethod
);
}
CorsConfiguration
corsConfig
=
initCorsConfiguration
(
handler
,
method
,
mapping
);
CorsConfiguration
corsConfig
=
initCorsConfiguration
(
handler
,
method
,
mapping
);
this
.
mappingDefinitions
.
put
(
method
,
new
MappingDefinition
<
T
>(
mapping
,
handlerMethod
,
directUrls
,
name
,
corsConfig
));
this
.
methodLookup
.
put
(
method
,
new
MappingDefinition
<
T
>(
mapping
,
handlerMethod
,
directUrls
,
name
,
corsConfig
));
}
finally
{
this
.
readWriteLock
.
writeLock
().
unlock
();
}
}
private
void
assertUniqueM
apping
(
HandlerMethod
h
andlerMethod
,
T
mapping
)
{
HandlerMethod
existing
=
this
.
mappingLookup
.
get
(
mapping
);
if
(
existing
!=
null
&&
!
existing
.
equals
(
h
andlerMethod
))
{
private
void
assertUniqueM
ethodMapping
(
HandlerMethod
newH
andlerMethod
,
T
mapping
)
{
HandlerMethod
handlerMethod
=
this
.
mappingLookup
.
get
(
mapping
);
if
(
handlerMethod
!=
null
&&
!
handlerMethod
.
equals
(
newH
andlerMethod
))
{
throw
new
IllegalStateException
(
"Ambiguous mapping. Cannot map '"
+
handlerMethod
.
getBean
()
+
"' method \n"
+
handlerMethod
+
"\nto "
+
mapping
+
": There is already '"
+
existing
.
getBean
()
+
"' bean method\n"
+
existing
+
" mapped."
);
"Ambiguous mapping. Cannot map '"
+
newHandlerMethod
.
getBean
()
+
"' method \n"
+
newHandlerMethod
+
"\nto "
+
mapping
+
": There is already '"
+
handlerMethod
.
getBean
()
+
"' bean method\n"
+
handlerMethod
+
" mapped."
);
}
MappingDefinition
<
T
>
definition
=
this
.
methodLookup
.
get
(
newHandlerMethod
.
getMethod
());
if
(
definition
!=
null
)
{
throw
new
IllegalStateException
(
"Cannot map "
+
newHandlerMethod
.
getMethod
()
+
"\nto "
+
mapping
+
".\n It is already mapped to "
+
definition
.
getMapping
());
}
}
private
List
<
String
>
extrac
tDirectUrls
(
T
mapping
)
{
private
List
<
String
>
ge
tDirectUrls
(
T
mapping
)
{
List
<
String
>
urls
=
new
ArrayList
<
String
>(
1
);
for
(
String
path
:
getMappingPathPatterns
(
mapping
))
{
if
(!
getPathMatcher
().
isPattern
(
path
))
{
...
...
@@ -503,13 +557,13 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
return
urls
;
}
private
void
addName
(
String
name
,
HandlerMethod
handlerMethod
)
{
private
void
add
Mapping
Name
(
String
name
,
HandlerMethod
handlerMethod
)
{
List
<
HandlerMethod
>
old
HandlerMethods
=
this
.
n
ameLookup
.
containsKey
(
name
)
?
this
.
n
ameLookup
.
get
(
name
)
:
Collections
.<
HandlerMethod
>
emptyList
();
List
<
HandlerMethod
>
old
List
=
this
.
mappingN
ameLookup
.
containsKey
(
name
)
?
this
.
mappingN
ameLookup
.
get
(
name
)
:
Collections
.<
HandlerMethod
>
emptyList
();
for
(
HandlerMethod
oldHandlerMethod
:
oldHandlerMethods
)
{
if
(
oldHandlerMethod
.
getMethod
().
equals
(
handlerMethod
.
getMethod
()))
{
for
(
HandlerMethod
current
:
oldList
)
{
if
(
handlerMethod
.
getMethod
().
equals
(
current
.
getMethod
()))
{
return
;
}
}
...
...
@@ -518,19 +572,69 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
logger
.
trace
(
"Mapping name="
+
name
);
}
int
size
=
oldHandlerMethods
.
size
()
+
1
;
List
<
HandlerMethod
>
definitions
=
new
ArrayList
<
HandlerMethod
>(
size
);
definitions
.
addAll
(
oldHandlerMethods
);
definitions
.
add
(
handlerMethod
);
this
.
nameLookup
.
put
(
name
,
definitions
);
List
<
HandlerMethod
>
newList
=
new
ArrayList
<
HandlerMethod
>(
oldList
.
size
()
+
1
);
newList
.
addAll
(
oldList
);
newList
.
add
(
handlerMethod
);
this
.
mappingNameLookup
.
put
(
name
,
newList
);
if
(
definitions
.
size
()
>
1
)
{
if
(
newList
.
size
()
>
1
)
{
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
"Mapping name clash for handlerMethods="
+
definitions
+
logger
.
debug
(
"Mapping name clash for handlerMethods="
+
newList
+
". Consider assigning explicit names."
);
}
}
}
public
void
unregister
(
HandlerMethod
handlerMethod
)
{
this
.
readWriteLock
.
writeLock
().
lock
();
try
{
MappingDefinition
<
T
>
definition
=
this
.
methodLookup
.
remove
(
handlerMethod
.
getMethod
());
if
(
definition
==
null
)
{
return
;
}
this
.
mappingLookup
.
remove
(
definition
.
getMapping
());
for
(
String
url
:
definition
.
getDirectUrls
())
{
List
<
T
>
list
=
this
.
urlLookup
.
get
(
url
);
if
(
list
!=
null
)
{
list
.
remove
(
definition
.
getMapping
());
if
(
list
.
isEmpty
())
{
this
.
urlLookup
.
remove
(
url
);
}
}
}
removeMappingName
(
definition
);
}
finally
{
this
.
readWriteLock
.
writeLock
().
unlock
();
}
}
private
void
removeMappingName
(
MappingDefinition
<
T
>
definition
)
{
String
name
=
definition
.
getName
();
if
(
name
==
null
)
{
return
;
}
HandlerMethod
handlerMethod
=
definition
.
getHandlerMethod
();
List
<
HandlerMethod
>
oldList
=
this
.
mappingNameLookup
.
get
(
name
);
if
(
oldList
==
null
)
{
return
;
}
if
(
oldList
.
size
()
<=
1
)
{
this
.
mappingNameLookup
.
remove
(
name
);
return
;
}
List
<
HandlerMethod
>
newList
=
new
ArrayList
<
HandlerMethod
>(
oldList
.
size
()
-
1
);
for
(
HandlerMethod
current
:
oldList
)
{
if
(!
current
.
equals
(
handlerMethod
))
{
newList
.
add
(
current
);
}
}
this
.
mappingNameLookup
.
put
(
name
,
newList
);
}
}
private
static
class
MappingDefinition
<
T
>
{
...
...
@@ -539,14 +643,14 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
private
final
HandlerMethod
handlerMethod
;
private
final
List
<
String
>
u
rls
;
private
final
List
<
String
>
directU
rls
;
private
final
String
name
;
private
final
CorsConfiguration
corsConfiguration
;
public
MappingDefinition
(
T
mapping
,
HandlerMethod
handlerMethod
,
List
<
String
>
u
rls
,
public
MappingDefinition
(
T
mapping
,
HandlerMethod
handlerMethod
,
List
<
String
>
directU
rls
,
String
name
,
CorsConfiguration
corsConfiguration
)
{
Assert
.
notNull
(
mapping
);
...
...
@@ -554,7 +658,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
this
.
mapping
=
mapping
;
this
.
handlerMethod
=
handlerMethod
;
this
.
urls
=
(
urls
!=
null
?
u
rls
:
Collections
.<
String
>
emptyList
());
this
.
directUrls
=
(
directUrls
!=
null
?
directU
rls
:
Collections
.<
String
>
emptyList
());
this
.
name
=
name
;
this
.
corsConfiguration
=
corsConfiguration
;
}
...
...
@@ -568,8 +672,8 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
return
this
.
handlerMethod
;
}
public
List
<
String
>
getUrls
()
{
return
this
.
u
rls
;
public
List
<
String
>
get
Direct
Urls
()
{
return
this
.
directU
rls
;
}
public
String
getName
()
{
...
...
spring-webmvc/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java
浏览文件 @
8f558e7c
/*
* Copyright 2002-201
2
the original author or authors.
* Copyright 2002-201
5
the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
...
...
@@ -16,10 +16,13 @@
package
org.springframework.web.servlet.handler
;
import
static
org
.
junit
.
Assert
.*;
import
java.lang.reflect.Method
;
import
java.util.Comparator
;
import
java.util.HashSet
;
import
java.util.Set
;
import
javax.servlet.http.HttpServletRequest
;
import
org.junit.Before
;
...
...
@@ -34,8 +37,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import
org.springframework.web.method.HandlerMethod
;
import
org.springframework.web.util.UrlPathHelper
;
import
static
org
.
junit
.
Assert
.*;
/**
* Test for {@link AbstractHandlerMethodMapping}.
*
...
...
@@ -77,7 +78,7 @@ public class HandlerMethodMappingTests {
@Test
public
void
patternMatch
()
throws
Exception
{
mapping
.
registerHandlerMethod
(
handler
,
method1
,
"/fo*"
);
mapping
.
registerHandlerMethod
(
handler
,
method
1
,
"/f*"
);
mapping
.
registerHandlerMethod
(
handler
,
method
2
,
"/f*"
);
HandlerMethod
result
=
mapping
.
getHandlerInternal
(
new
MockHttpServletRequest
(
"GET"
,
"/foo"
));
assertEquals
(
method1
,
result
.
getMethod
());
...
...
@@ -92,7 +93,7 @@ public class HandlerMethodMappingTests {
}
@Test
public
void
testD
etectHandlerMethodsInAncestorContexts
()
{
public
void
d
etectHandlerMethodsInAncestorContexts
()
{
StaticApplicationContext
cxt
=
new
StaticApplicationContext
();
cxt
.
registerSingleton
(
"myHandler"
,
MyHandler
.
class
);
...
...
@@ -110,6 +111,18 @@ public class HandlerMethodMappingTests {
assertEquals
(
2
,
mapping2
.
getHandlerMethods
().
size
());
}
@Test
public
void
unregister
()
throws
Exception
{
String
key
=
"foo"
;
mapping
.
registerHandlerMethod
(
handler
,
method1
,
key
);
HandlerMethod
handlerMethod
=
mapping
.
getHandlerInternal
(
new
MockHttpServletRequest
(
"GET"
,
key
));
assertEquals
(
method1
,
handlerMethod
.
getMethod
());
mapping
.
unregisterHandlerMethod
(
handlerMethod
);
assertNull
(
mapping
.
getHandlerInternal
(
new
MockHttpServletRequest
(
"GET"
,
key
)));
}
private
static
class
MyHandlerMethodMapping
extends
AbstractHandlerMethodMapping
<
String
>
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录