Spring(十七):获取ApplicationContext方式,获取所有Bean和RequestMapping
Spring 项目经常需要拿到上下文,通过上下文来获取 IoC 容器中注册的 Bean。
获取上下文有好几种方式,可以实现 ApplicationContextAware 接口,可以通过 ServletContext 获取,而通过 ContextLoader 来获取上下文在 Spring Boot 中并不适用,适用于 Spring 项目。
查看容器中所有Bean
要查看所有 Bean 必须先拿到上下文:ApplicationContext
。
1 |
|
拿到上下文调用getBeanDefinitionNames()
方法,返回一个装有 beanId 的数组。
1 |
|
获取所有RequestMapping
WebApplicationContext 可以获得请求处理映射器 RequestMappingHandlerMapping,再可以获得所有映射的 URL。
1 | RequestMappingHandlerMapping mapping = webApplicationContext.getBean(RequestMappingHandlerMapping.class); |
获取ApplicationContext的几种方式
SpringApplication.run返回
Spirng Boot 应用启动入口 main 方法中的 SpringApplication.run 返回的就是 ApplicationContext,可以存起来用。
1 |
|
注入ApplicationContext直接使用
1 |
|
该方法说明 ApplicationContext 已经是 Spring 管理的 Bean 了,也可以直接在构造方法中注入,所以在自定义 starter、工具或配置时,可以在构造方法中注入来使用。
通过ApplicationContextAware实现
实现ApplicationContextAware接口
实现 ApplicationContextAware 接口,重写setApplicationContext(ApplicationContext context) 方法,并保存 ApplicationContext 对象。
Spring 初始化时,会通过该方法将 ApplicationContext 对象注入。
1 |
|
备注:实现 ApplicationContextAware 的类必须在XML
或JavaConfig
里配置为 Bean。
继承 ApplicationObjectSupport
ApplicationObjectSupport 也是实现 ApplicationContextAware 接口的抽象类。
继承自抽象类来 ApplicationObjectSupport,该类提供 getApplicationContext()
方法获取 ApplicationContext 。
Spring 初始化时,会通过该抽象类的 setApplicationContext(ApplicationContext context) 方法将 ApplicationContext 对象注入。
继承 WebApplicationObjectSupport
WebApplicationObjectSupport 是继承 ApplicationObjectSupport 的抽象类。Web 应用中使用,调用 getWebApplicationContext() 获取 WebApplicationContext。
通过 DispatcherServlet 获取
Spring MVC 可以通过 DispatcherServlet 直接获取 WebApplicationContext。DispatcherServlet 通过父类 FrameworkServlet 实现了 ApplicationContextAware 接口。
1 |
|
通过 WebApplicationContextUtils 获取
先获取 ServletContext
通过 Controller 接口入参 HttpServletRequest 获取:
1 | ServletContext servletContext = httpServletRequest.getServletContext(); |
通过 RequestContextHolder 获取 HttpServletRequest:
1 | // 通过 RequestContextHolder 获取 HttpServletRequest |
Spring MVC 通过 DispatcherServlet 来获取:
1 |
|
通过 WebApplicationContextUtils 获取
1 | // 1 找不到时会抛出异常 |
getRequiredWebApplicationContext 方法实际调的是 getWebApplicationContext 方法,但多了一个入参
1 | public static WebApplicationContext getRequiredWebApplicationContext(ServletContext sc) { |
ContextLoader上下文加载器
ContextLoader:Spring 上下文加载器,为根应用上下文执行实际的初始化操作,由子类ContextLoaderListener 调用。
ContextLoaderListener 的本质是个监听器,继承了 ContextLoader,实现了 ServletContextListener,也就是说在监听到 Servlet 应用启动事件时,会为 Servlet 上下文初始化 Spring 的 Web 应用上下文。
1 | WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext(); |
ContextLoaderListener:
1 |
|
ContextLoader:
1 | public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { |
注意:Spring Boot 使用内置的 Tomcat 走的不是这个逻辑,这样拿到的 webApplicationContext 是空的。
跟踪源码后发现启动过程并没有调用initWebApplicationContext()
,也就是ContextLoaderListener
监听器类根本就没执行,而在 SSM 项目是在web.xml
文件配置该监听器。
返回到Spring Boot 入口类,跟踪启动过程SpringApplication.run()
的源码,可以看到在启动初始化了 14 个监听器中,确实没有ContextLoaderListener
,启动过程中也没有执行入口类继承的父类SpringBootServletInitializer
里的onStartup()
方法。
所以此方式不适合使用 Spring Boot 内置的Tomcat启动的项目,在外部Tomcat的使用待验证。
手动创建ApplicationContext
AbstractRefreshableWebApplicationContext:可刷新Web应用上下文抽象,相当于重新加载一次。
注意,Spring 上下文在服务器启动时就会初始化,这里再重新加载,是非常耗资源且低效的,通常只在 Spring 独立应用中使用,或在测试时需要加载外部文件创建 Spring 上下文时使用。
- AnnotationConfigApplicationContext:从Java的配置类中加载上下文定义,适用于Java注解的方式
- ClassPathXmlApplicationContext:从类路径下XML配置文件中加载上下文定义,适用于 XML 配置的方式
- FileSystemXmlApplicationContext:从文件系统下的 XML 配置文件中加载上下文定义,适用于指定系统盘符的文件路径中加载XML配置文件
- AnnotationConfigWebApplicationContext:适用于 Web 应用,使用注解方式加载上下文
- XmlWebApplicationContext:适用于 Web 应用,从Web应用下的XML配置文件加载上下文定义
1 | public class ApplicationContext { |
Spring(十七):获取ApplicationContext方式,获取所有Bean和RequestMapping
http://blog.gxitsky.com/2018/05/02/Spring-17-ApplicationContext/