如何在Spring MVC中找到所有的控制器?

14

我希望能够提供一些运行时生成的API文档,因此我想要迭代所有的Spring MVC控制器。所有的控制器都使用Spring的@Controller注解进行了注释。目前我的做法是这样的:

for (final Object bean: this.context.getBeansWithAnnotation(
        Controller.class).values())
{
    ...Generate controller documentation for the bean...
}

但是这段代码的第一次调用非常慢。我想知道Spring是否遍历了类路径中的所有类,而不仅仅是检查定义的bean。当上述代码运行时,控制器已经加载,日志显示了它们所有的请求映射,因此Spring MVC必须已经知道它们全部并且必须有更快的方法来获取它们的列表。但是怎么做呢?


我想知道为什么你需要那个信息,因为你已经在注释@Controller了。 - ant
3
他已经非常清楚地在问题中提到,他想为那些控制器生成文档。 - Japan Trivedi
我在这里提供的答案 here 也可以实现这个功能。 - Jose Quijada
2个回答

38

我喜欢@Japs建议的方法,但也想推荐一种替代方法。 这基于您的观察结果,即Spring已经扫描了类路径,并配置了控制器和请求映射方法,此映射保留在handlerMapping组件中。 如果您正在使用Spring 3.1,则此handlerMapping组件是RequestMappingHandlerMapping的实例,您可以查询以找到handlerMappedMethods和相关的控制器,按照以下方式执行(如果您使用旧版本的Spring,则应该能够使用类似的方法):

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

@Controller
public class EndpointDocController {
 private final RequestMappingHandlerMapping handlerMapping;
 
 @Autowired
 public EndpointDocController(RequestMappingHandlerMapping handlerMapping) {
  this.handlerMapping = handlerMapping;
 }
  
 @RequestMapping(value="/endpointdoc", method=RequestMethod.GET)
 public void show(Model model) {
  model.addAttribute("handlerMethods", this.handlerMapping.getHandlerMethods());
 } 
}

我在这个网址提供了更多细节信息:http://biju-allandsundry.blogspot.com/2012/03/endpoint-documentation-controller-for.html

这是基于Spring Source的Rossen Stoyanchev关于Spring 3.1的演示。


1
这很棒。我会选择这个。 - Sean Patrick Floyd
使用/定义@Autowired private RequestMappingHandlerMapping handlerMapping; 在类中也可以工作,而不是定义final并将其作为参数传递,并在构造函数中初始化。稍后如果您使用自定义用户制作的对象(显然不是控制器)进行初始化,则可能会出现问题。 - Merv

17

我几个月前也遇到过类似的需求,我使用以下代码片段实现了它。

ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        scanner.addIncludeFilter(new AnnotationTypeFilter(Controller.class));
        for (BeanDefinition beanDefinition : scanner.findCandidateComponents("com.xxx.yyy.controllers")){
            System.out.println(beanDefinition.getBeanClassName());
        }
你也可以在你的控制器中这样做。
更新了代码片段。删除了不必要的代码,并仅显示控制器的类名,以便更好地理解。 希望这能帮到你。干杯。

好的代码片段(+1)。但我认为它太底层了。我的意思是这个扫描。我相信getBeansWithAnnotation()的实现应该在内部使用扫描器。 - AlexR
也许你是对的。但他想要更快的方法来实现这个。我已经使用了上面的代码片段,对我来说它并不慢。这就是为什么我建议使用它。而且这个扫描器类是由Spring自己提供的,所以在我看来它并不低级。 - Japan Trivedi
1
非常好用,比getBeansWithAnnotation()快得多。谢谢! - kayahr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接