Spring MVC 之 HandlerMapping 源码分析与应用(获取所有URI)

整理这篇文章由两个因素引发:

  • 一个是参与的微服务项目涉及到权限管理应用到了 HandlerMapping ,使用自定义注解,自动或手动拿到各个微服务所有自定义的 Controller RequestMapping(URI)同步到权限管理模块。

  • 二是开发的项目报了异常,打印的异常信息比较有意思,就跟踪源码查到信息也是来自于 HandlerMapping,这些信息可以自己获取后应用在拦截器或 Controller 层的 AOP 中。

    备注:已使用 AOP 拿到类似到源码抛出的打印的异常信息,但没有源码抛出的异常信息完美优雅。

HandlerMapping 是 Spirng MVC 的执行流程中需要用到的一个组件,用于获取 Handler 配置的所有相关的对象,包括 Handler 对象对应的拦截器,把这些对象封装到 HandlerExecutionChain(处理执行器链) 对象当中返回。可参考 Spring MVC 的执行流程

HandlerMapping 有多个实现,可看下面的类图,而 RequestMappingHandlerMapping 是用得比较多的,它基于 @Controller 注解类上的 @RequestMapping 注解,从类型和方法级别创建请求映射信息 RequestMappingInfo。

HandlerMapping

HandlerMapping 是一个接口,里面主要有一个获取处理器执行链的方法 *HandlerExecutionChain getHandler(HttpServletRequest request)*,此接口由定义 请求处理器对象 之间映射的对象实现。

Handler(处理对象)将始终被包装成 HandlerExecutionChain(处理器执行链)实现,其中可以包含一些 HandlerInterceptor 实例。

HandlerMapping 主要实现

HandlerMapping 类图

HandlerMapping 的主要实现类主要有以下几个:

  • WelcomePageHandlerMapping:默认的欢迎首页(index.html)映射器。

  • SimpleUrlHandlerMapping:将 URLs 映射到请求处理器的 bean,支持映射到 bean 实例 和 bean names。

    语法:PATH=HANDLER_BEAN_NAME,示例如下。

    1
    2
    /welcome.html=ticketController
    /show.html=ticketController
  • RequestMappingHandlerMapping:基于 @Controller 注解类上的 @RequestMapping 注解,从类型和方法级别创建请求映射信息 RequestMappingInfo。开发中用到最多的。

  • BeanNameUrlHandlerMapping:从 URLs 映射到名称以斜杠("/")开头的 bean,这是 DispatcherServlet 和 RequestMappingHandlerMapping 一起使用的默认实现。

    例如,一个进入的请求 URL /foo 映射到一个名为 /foo 的处理器,或多个如 /foo, /foo2 映射到单个处理器。

    支持直接匹配和模式匹配,如 /test 映射到 /test/test 映射到 /t*

HandlerMapping 源码分析

  1. DispatcherServlet 里的 doService 方法中调用 doDispatch 方法。

  2. doDispatch 方法中获取处理器执行链,实际是处理器映射器,被包装成了 HandlerExecutionChain。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
    ModelAndView mv = null;
    Exception dispatchException = null;

    try {
    processedRequest = checkMultipart(request);
    multipartRequestParsed = (processedRequest != request);

    // Determine handler for the current request.
    // 决定那个处理器来处理当前请求
    mappedHandler = getHandler(processedRequest);

    //...............
    }
    }
    }
  3. 应用启动完成之后,在接收到第一个请求(HttpServletRequest)时初始化 WebApplicationContext,初始化同时调用 onRefresh 方法执行初始化 Servlet 需要用到的策略对象,其中包括初始化处理器映射器(HandlerMapping),实际是将 Spring 容器(ApplicationContext 上下文中)中实现 HandlerMapping 接口的 Bean 装入一个 List 。

    DispatcherServlet.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    @Override
    protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
    }

    protected void initStrategies(ApplicationContext context) {
    // 初始化文件上传解析器
    initMultipartResolver(context);
    // 初始化本地解析器
    initLocaleResolver(context);
    // 初始化主题解析器
    initThemeResolver(context);
    // 初始化处理器映射器
    initHandlerMappings(context);
    // 初始化处理器适配器
    initHandlerAdapters(context);
    // 初始化处理器异常解决器
    initHandlerExceptionResolvers(context);
    // 初始化请求到视图名的翻译器
    initRequestToViewNameTranslator(context);
    // 初始化视图解析器
    initViewResolvers(context);
    initFlashMapManager(context);
    }

    initHandlerMappings(context) 初始化 处理器映射器,保存到 handlerMappings

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    @Nullable
    private List<HandlerMapping> handlerMappings;

    private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;

    if (this.detectAllHandlerMappings) {
    // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
    // 检查 ApplicationContext 中所有 HandlerMappings
    Map<String, HandlerMapping> matchingBeans =
    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
    if (!matchingBeans.isEmpty()) {
    // 封装成一个 List
    this.handlerMappings = new ArrayList<>(matchingBeans.values());
    // We keep HandlerMappings in sorted order.
    AnnotationAwareOrderComparator.sort(this.handlerMappings);
    }
    }
    else {
    try {
    HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
    this.handlerMappings = Collections.singletonList(hm);
    }
    catch (NoSuchBeanDefinitionException ex) {
    // Ignore, we'll add a default HandlerMapping later.
    }
    }

    // Ensure we have at least one HandlerMapping, by registering
    // a default HandlerMapping if no other mappings are found.
    if (this.handlerMappings == null) {
    this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
    if (logger.isTraceEnabled()) {
    logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
    "': using default strategies from DispatcherServlet.properties");
    }
    }
    }

    然后遍历 List<HandlerMapping>,获取与请求匹配的处理器。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    @Nullable
    private List<HandlerMapping> handlerMappings;

    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
    for (HandlerMapping mapping : this.handlerMappings) {
    // 根据请求获取处理器映射器
    HandlerExecutionChain handler = mapping.getHandler(request);
    if (handler != null) {
    return handler;
    }
    }
    }
    return null;
    }

    getHandler(request)底层是根据 request 的 URI 查找处理器。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @Override
    @Nullable
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    //根据给定的 request 获取处理器
    Object handler = getHandlerInternal(request);
    if (handler == null) {
    handler = getDefaultHandler();
    }
    if (handler == null) {
    return null;
    }
    // Bean name or resolved handler?
    if (handler instanceof String) {
    String handlerName = (String) handler;
    handler = obtainApplicationContext().getBean(handlerName);
    }
    // 包装成处理器执行链
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    //...........省略...........
    return executionChain;
    }

    RequestMappingInfoHandlerMapping.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Override
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
    try {
    // 调用 AbstractHandlerMethodMapping 父类方法
    return super.getHandlerInternal(request);
    }
    finally {
    ProducesRequestCondition.clearMediaTypesAttribute(request);
    }
    }

    AbstractHandlerMethodMapping.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    private final MappingRegistry mappingRegistry = new MappingRegistry();

    @Override
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    //获取请求 URI
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    request.setAttribute(LOOKUP_PATH, lookupPath);
    this.mappingRegistry.acquireReadLock();
    try {
    //根据 URI 找到其映射的处理器
    HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
    return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
    this.mappingRegistry.releaseReadLock();
    }
    }

    /**
    * 查找当前请求的最佳匹配处理程序方法。 如果找到多个匹配项,则选择最佳匹配项。
    * lookupPath
    */
    @Nullable
    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    // 重点, 从初始化的 mappingRegistry 中获取匹配的路径
    List<T> directPathMatches = this.mappingRegistry .getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
    // 匹配处理
    addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
    // No choice but to go through all mappings...
    addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }

    if (!matches.isEmpty()) {
    Match bestMatch = matches.get(0);
    if (matches.size() > 1) {
    Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
    // 排序
    matches.sort(comparator);
    // 获取最佳匹配
    bestMatch = matches.get(0);
    if (logger.isTraceEnabled()) {
    logger.trace(matches.size() + " matching mappings: " + matches);
    }
    if (CorsUtils.isPreFlightRequest(request)) {
    return PREFLIGHT_AMBIGUOUS_MATCH;
    }
    Match secondBestMatch = matches.get(1);
    // 存在相同的两个,抛出异常
    if (comparator.compare(bestMatch, secondBestMatch) == 0) {
    Method m1 = bestMatch.handlerMethod.getMethod();
    Method m2 = secondBestMatch.handlerMethod.getMethod();
    String uri = request.getRequestURI();
    throw new IllegalStateException(
    "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
    }
    }
    request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
    handleMatch(bestMatch.mapping, lookupPath, request);
    // 返回最佳匹配的处理器方法
    return bestMatch.handlerMethod;
    }
    else {
    return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
    }

    /**
    * MappingRegistry 是 AbstractHandlerMethodMapping 的内部类
    * 维护与处理器方法的所有映射、公开方法以执行查找并提供并发访问的注册表
    * MappingRegistry 的初始化见下面章节
    */
    class MappingRegistry {

    private final Map<T, MappingRegistration<T>> registry = new HashMap<>();

    private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();

    private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();

    private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();

    private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();

    private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    //........省略.........
    }
  4. 前提是,HandlerMapping 的实现类在注册为 Bean 后会执行最终的初始化配置,即调 afterPropertiesSet方法执行 initHandlerMethods()

    initHandlerMethods 方法遍历 ApplicationContext 中的 Bean,检测是否为处理器方法,即判断这个 bean 是否有 @Controller 或 @RequestMapping 注解,如果有则认为是处理器控制器,然后封装处理器方法与映射信息,将其注册(存储)到 MappingRegistry 中的各个 Map 或 List 中,完成 URI处理器映射的初始化。

    AbstractHandlerMethodMapping.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    @Override
    public void afterPropertiesSet() {
    //初始化
    initHandlerMethods();
    }

    protected void initHandlerMethods() {
    // 遍历所有的 beanName
    for (String beanName : getCandidateBeanNames()) {
    if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
    // 根据 beanName 判断处理
    processCandidateBean(beanName);
    }
    }
    handlerMethodsInitialized(getHandlerMethods());
    }

    protected void processCandidateBean(String beanName) {
    Class<?> beanType = null;
    try {
    beanType = obtainApplicationContext().getType(beanName);
    }
    catch (Throwable ex) {
    // An unresolvable bean type, probably from a lazy bean - let's ignore it.
    if (logger.isTraceEnabled()) {
    logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
    }
    }
    // 判断是否为处理器
    if (beanType != null && isHandler(beanType)) {
    // 检查处理器方法
    detectHandlerMethods(beanName);
    }
    }

    RequestMappingHandlerMapping.java

    判断是否为处理器

    1
    2
    3
    4
    5
    6
    @Override
    protected boolean isHandler(Class<?> beanType) {
    // 判断是否为处理器,即是否有 @Controller 或 @RequestMapping 注解
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
    AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }

    AbstractHandlerMethodMapping.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    /**
    * 检查处理器方法, handler 是 beanName
    */
    protected void detectHandlerMethods(Object handler) {
    // 拿到 bean 的 Class 对象, 即 Controller 类对象
    Class<?> handlerType = (handler instanceof String ?
    obtainApplicationContext().getType((String) handler) : handler.getClass());

    if (handlerType != null) {
    Class<?> userType = ClassUtils.getUserClass(handlerType);
    // 获取方法, Key是方法对象, value是RequestMappingInfo对象,即 @RequestMapping注解的信息
    // RequestMappingInfo 包含路径,请求类型,params,head,consume,produce等信息
    Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
    (MethodIntrospector.MetadataLookup<T>) method -> {
    try {
    return getMappingForMethod(method, userType);
    }
    catch (Throwable ex) {
    throw new IllegalStateException("Invalid mapping on handler class [" +
    userType.getName() + "]: " + method, ex);
    }
    });
    if (logger.isTraceEnabled()) {
    logger.trace(formatMappings(userType, methods));
    }
    methods.forEach((method, mapping) -> {
    // 遍历方法,重新封装成 Method 对象,实际取的就是 method 对象
    Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
    // 注册处理器方法
    registerHandlerMethod(handler, invocableMethod, mapping);
    });
    }
    }

    /**
    * 注册处理器方法及其唯一映射。在启动时为每个检测到的处理器方法调用
    */
    protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    this.mappingRegistry.register(mapping, handler, method);
    }
  5. MappingRegistry 是 AbstractHandlerMethodMapping 的内部类,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    /**
    * MappingRegistry 是内部类
    * 注册处理器方法及其唯一映射
    * 实际就是抽取处理器方法信息和映射信息, 封装成不同的 List 和 Map, 完成初始化
    * 以备后续有请求进来后, 根据 request 直接从这些 List 或 Map 中找到映射的处理器
    */
    class MappingRegistry {

    private final Map<T, MappingRegistration<T>> registry = new HashMap<>();

    private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();

    private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();

    private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();

    private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();

    private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    //........省略......

    public void register(T mapping, Object handler, Method method) {
    // Assert that the handler method is not a suspending one.
    if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
    throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
    }
    this.readWriteLock.writeLock().lock();
    try {
    HandlerMethod handlerMethod = createHandlerMethod(handler, method);
    validateMethodMapping(handlerMethod, mapping);
    //mapping
    this.mappingLookup.put(mapping, handlerMethod);

    List<String> directUrls = getDirectUrls(mapping);
    for (String url : directUrls) {
    // url
    this.urlLookup.add(url, mapping);
    }

    String name = null;
    if (getNamingStrategy() != null) {
    name = getNamingStrategy().getName(handlerMethod, mapping);
    // mappingName
    addMappingName(name, handlerMethod);
    }

    CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
    if (corsConfig != null) {
    // cors
    this.corsLookup.put(handlerMethod, corsConfig);
    }
    // 映射的注册信息
    this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
    }
    finally {
    this.readWriteLock.writeLock().unlock();
    }
    }
    //.........省略............
    }

RequestMappingHandlerMapping

获取请求映射处理器

可以用于请求拦截器 或 Controller 层的 AOP ,统一打印请求映射处理信息。

1
2
3
4
5
6
7
8
9
10
11
12
@Autowired
@Qualifier(value = "requestMappingHandlerMapping")
private HandlerMapping requestMappingHandlerMapping;

// 处理器执行链
HandlerExecutionChain handlerExecutionChain = requestMappingHandlerMapping.getHandler(request);
HandlerMethod handlerMethod = (HandlerMethod) handlerExecutionChain.getHandler();
MethodParameter[] methodParameters = handlerMethod.getMethodParameters();
for (MethodParameter parameter : methodParameters) {
String string = parameter.getExecutable().toGenericString();
logger.info("Request Controller:{}", string);
}

输出信息:

1
Request Controller:public com.clearofchina.core.model.ResponseModel com.clearofchina.hisp.controller.FileInfoController.detail(com.clearofchina.hisp.entity.vo.IdVO)

获取所有映射的 URI

获取所有 @Controller 注解类上的 @RequestMapping 注解映射的 URI。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;

//@Autowired
//private WebApplicationContext webApplicationContext;

//RequestMappingHandlerMapping handlerMapping = webApplicationContext.getBean(RequestMappingHandlerMapping.class);

//获取 WebApplicationContext 来获取 requestMappingHandlerMapping
//WebApplicationContext webApplicationContext = (WebApplicationContext) request.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
//RequestMappingHandlerMapping handlerMapping = webApplicationContext.getBean("requestMappingHandlerMapping")

Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
List<Map<String, String>> list = new ArrayList<>();
Set<String> uriSet = new HashSet<>();
for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethodMap.entrySet()) {
Map<String, String> controllerMap = new HashMap<>();

RequestMappingInfo mappingInfo = entry.getKey();
HandlerMethod handlerMethod = entry.getValue();

Set<String> patternSet = mappingInfo.getPatternsCondition().getPatterns();
Set<RequestMethod> methodSet = mappingInfo.getMethodsCondition().getMethods();
// uriSet.addAll(patterns);
for (String pattern : patternSet) {
uriSet.add(pattern);
controllerMap.put("url", pattern);
}

// 类注解
RequestMapping annotation = handlerMethod.getMethod().getDeclaringClass().getAnnotation(RequestMapping.class);
// 方法注解
RequestMapping methodAnnotation = handlerMethod.getMethodAnnotation(RequestMapping.class);

// 类名
controllerMap.put("className", handlerMethod.getMethod().getDeclaringClass().getName());
// 方法名
controllerMap.put("method", handlerMethod.getMethod().getName());
// 方法类型
for (RequestMethod requestMethod : methodSet) {
controllerMap.put("type", requestMethod.toString());
}
list.add(controllerMap);
}
logger.info("url set:" + JSON.toJSONString(uriSet));
logger.info("url controller:" + JSON.toJSONString(list));

Set<String> uriSet 打印:

1
2
3
4
5
6
[
"/error",
"/fileInfo/detail",
"/downloadLog/pageList",
"/downloadLog/detail"
]

List<Map<String, String>> list 打印:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[
{
"method":"detail",
"className":"com.clearofchina.hisp.controller.DownloadLogController",
"type":"GET",
"url":"/downloadLog/detail"
},
{
"method":"pageList",
"className":"com.clearofchina.hisp.controller.DownloadLogController",
"type":"GET",
"url":"/downloadLog/pageList"
},
{
"method":"detail",
"className":"com.clearofchina.hisp.controller.FileInfoController",
"type":"GET",
"url":"/fileInfo/detail"
},
{
"method":"error",
"className":"org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController",
"url":"/error"
},
{
"method":"errorHtml",
"className":"org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController",
"url":"/error"
}
]

获取所有Controller的beanName

1
2
3
@Autowired
private WebApplicationContext webApplicationContext;
String[] beanNames = webApplicationContext.getBeanNamesForAnnotation(Controller.class);

获取Spring容器中所有beanName

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Autowired
private WebApplicationContext webApplicationContext;
String[] beanNames = webApplicationContext.getBeanDefinitionNames();

// 或者
@Component
public class SpringContextHolder implements ApplicationContextAware {

private static ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextHolder.applicationContext = applicationContext;
}

public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}
String[] beanNames = SpringContextHolder.getApplicationContext().getBeanDefinitionNames();

相关参考

  1. SpringMVC(关于HandlerMapping执行流程原理分析)

Spring MVC 之 HandlerMapping 源码分析与应用(获取所有URI)

http://blog.gxitsky.com/2020/05/19/SpringMVC-36-requestHandlerMapping/

作者

光星

发布于

2020-05-19

更新于

2022-06-17

许可协议

评论