Spring IOC 容器获取与使用方式汇总:BeanFactory、ApplicationContext、获取项目全部URL
目录BeanFactory ( IOC 容)概述BeanFactoryAwareApplicationContextAwareBeanFactory ( IOC 容)概述1、org.springframework.beans.factory.BeanFactory 是一个 Factory(工厂),也就是 IOC 容器/对象工厂,Spring 中所有的 bean 都是由 Bean...
目录
BeanFactory & ApplicationContext IOC 容器概述
BeanFactoryAware 获取 BeanFactory
ApplicationContextAware 获取 ApplicationContext
WebApplicationContextUtils 工具类获取IOC容器
BeanFactory & ApplicationContext IOC 容器概述
1、org.springframework.beans.factory.BeanFactory 是一个 Factory(工厂),也就是 IOC 容器/对象工厂,Spring 中所有的 bean 都是由 BeanFactory(也就是IOC容器)来进行管理的。
2、可以使用 @Autowired、@Resource 注解来从 Spring 容器中自动获取实例,也可以手动从容器中获取。无论是以前用 xml 配置文件来配置 <bean>、还是后来使用 @Bean、@Component ...注解,都是为了将对象交由 Spring 容器管理。
3、BeanFactory 作为 IOC 功能的顶级接口,提供了各种不同的实现,IOC 作为 Spring 的核心功能之一,所以这些 API 也是很常见的。
4、ApplicationContext
是 BeanFactory 的扩展,功能得到了进一步增强,比如更易与 Spring AOP 集成、消息资源处理(国际化处理)、事件传递及各种不同应用层的 context 实现(如针对 web 应用的 WebApplicationContext)。
5、只要获取了 BeanFactory 或 ApplicationContext,则可以随意获取容器中的任意实例(bean),推荐使用 ApplicationContext。
//这两行代码一定不陌生
BeanFactory bf = new ClassPathXmlApplicationContext("student.xml");
Student studentBean = (Student) bf.getBean("studentBean");
//BeanFactory 在 spring-beans-x.x.x.RELEASE.jar 包下
Object getBean(String name) | 返回指定名称的 bean 实例,默认为单例。 如果没有具有指定名称的bean,则引发 NoSuchBeanDefinitionException 如果无法获取bean,则抛出 BeansException |
<T> T getBean(String name, Class<T> requiredType) | 在 get(String name) 的基础上加上了requiredType类型限制,可以是接口或超类。 如果bean不是所需类型,则引发BeannotofRequiredTypeException |
<T> T getBean(Class<T> requiredType) | 返回唯一匹配给定对象类型的bean实例(如果有). bean 必须匹配参数RequiredType类型,可以是接口或超类 如果找到给定类型的多个bean,则引发nouniqueBeanDefinitionException |
boolean containsBean(String name) | 返回是否存在具有给定名称的bean. |
boolean isSingleton(String name) | 返回此bean是否是单例。如果没有具有给定名称的bean,则引发nosuchbeanDefinitionException |
Class<?> getType(String name) | 返回bean的类型,如果不能确定,则返回 NULL。 如果没有具有给定名称的bean,则引发nosuchbeanDefinitionException |
BeanFactoryAware 获取 BeanFactory
1、对于 BeanFactory 管理的 Bean,怎么获取它然后使用呢?使用 @Autowired、@Resource 注解来注入是最常见的操作,也是必须掌握的技能。
2、 使用 @Autowired、@Resource 注解的类自己首先必须是 Spring 组件 @Component 才能注入,而有时候想在项目中的任意位置都能获取容器中的实例进行使用,比如想在某个 XxxUtils 中使用某个 @Service 标识的实例,这时把 XxxUtils 标识为 @Component ,然后使用 @Resource 注入实例,这种方式看起来没有使用代码直接从 BeanFactory 容器中获取实例方便。
3、显然只要拿到了 BeanFactory 对象,就可以使用它的 getBean 方法从容器中获取 bean 实例,而获取 BeanFactory 实例的一个最简单的方式就是实现 BeanFactoryAware 接口。
package org.springframework.beans.factory;
// BeanFactoryAware 接口只要一个方法
public interface BeanFactoryAware extends Aware {
/**初始化回调方法,spring 会自动将 BeanFactory 注入进行,我们接收之后即可使用 BeanFactory*/
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
4、自定义一个工厂类/工具类/助手类 实现 BeanFactoryAware 接口,有了它,则可以在项目中的任意位置传入 bean 名称或者类型来轻松获取容器中的实例(Jdk 8 + Spring Boot 2.1.6):
/**
* 1、实现 BeanFactoryAware 接口,重写 setBeanFactory(BeanFactory beanFactory)
* 2、本类必须是 Spring 组件,所以加上 @Component 注解
* 3、spring 容器启动实例化本类的时候,会自动执行回调方法 setBeanFactory(BeanFactory beanFactory) 将 BeanFactory 注入
* 4、获取了 BeanFactory 之后,则可以使用它的任意方法了,比如各种 getBean
*/
@Component
public class BeanFactoryHelper implements BeanFactoryAware {
private static BeanFactory beanFactory;
/**
* 重写 BeanFactoryAware 接口的方法
* @param beanFactory :参数赋值给本地属性之后即可使用 BeanFactory
* @throws BeansException
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/**
* 根据名称获取容器中的对象实例
* @param beanName :注入的实例必须已经存在容器中,否则抛异常:NoSuchBeanDefinitionException
* @return
*/
public static Object getBean(String beanName) {
return beanFactory.getBean(beanName);
}
/**
* 根据 class 获取容器中的对象实例
* @param requiredType :被注入的必须已经存在容器中,否则抛异常:NoSuchBeanDefinitionException
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> requiredType) {
return beanFactory.getBean(requiredType);
}
/**
* 判断 spring 容器中是否包含指定名称的对象
* @param beanName
* @return
*/
public static boolean containsBean(String beanName) {
return beanFactory.containsBean(beanName);
}
//其它需求皆可参考 BeanFactory 接口和它的实现类
}
4、控制层代码演示如下:
/**
* BeanFactoryAware + BeanFactory 获取 BeanFactory
* http://localhost:8080/application/context3
* @return
*/
@GetMapping("application/context3")
@SuppressWarnings("Duplicates")
public Map<String, Object> applicationContext3() {
PhoneController phoneController = BeanFactoryHelper.getBean(PhoneController.class);
List<Map<String, Object>> mapList = phoneController.userList();
Map<String, Object> dataMap = new HashMap<>(4);
dataMap.put("mapList", mapList);
return dataMap;
}
ApplicationContextAware 获取 ApplicationContext
1、上面已经说过 ApplicationContext 接口是 BeanFactory 接口的扩展,功能得到了进一步增强,能使用的方法也更多。
2、BeanFactory 对应 BeanFactoryAware,ApplicationContext 对应 ApplicationContextAware ,使用起来完全同理。
/**
* 1、spring 容器启动的时候会自动创建 ApplicationContextHelper 实例
* 2、然后调用 setApplicationContext 回调方法自动注入 ApplicationContext
* 3、有了 ApplicationContext 就可以 getBean 了
*/
@Component
public class ApplicationContextHelper implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 根据名称获取容器中的对象实例
* @param beanName :注入的实例必须已经存在容器中,否则抛异常:NoSuchBeanDefinitionException
* @return
*/
public static Object getBean(String beanName) {
return applicationContext.getBean(beanName);
}
/**
* 根据 class 获取容器中的对象实例
* @param requiredType :被注入的必须已经存在容器中,否则抛异常:NoSuchBeanDefinitionException
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
/**
* 判断 spring 容器中是否包含指定名称的对象
* @param beanName
* @return
*/
public static boolean containsBean(String beanName) {
return applicationContext.containsBean(beanName);
}
}
/**
* ApplicationContextAware + ApplicationContext 获取 ApplicationContext
* http://localhost:8080/application/context4
* @return
*/
@GetMapping("application/context4")
@SuppressWarnings("Duplicates")
public Map<String, Object> applicationContext4() {
PhoneController phoneController = ApplicationContextHelper.getBean(PhoneController.class);
List<Map<String, Object>> mapList = phoneController.userList();
Map<String, Object> dataMap = new HashMap<>(4);
dataMap.put("mapList4", mapList);
return dataMap;
}
直接注入获取 IOC 容器
/**
* Spring 默认已经提供了 IOC 容器(BeanFactory & ApplicationContext) 的实例,可以直接注入使用。
* 注意:从容器里面获取自己是没有的,但是可以直接注入使用。
*/
@Resource
private ApplicationContext applicationContext;
@Resource
private BeanFactory beanFactory;
@Resource
private WebApplicationContext applicationContext;
@Bean 添加实例时参数注入容器
/**
* 应用配置类
*
* @author wangMaoXiong
* @version 1.0
* @date 2022/4/21 21:28
*/
@Configuration
public class AppConfig {
/**
* ========= 自定义 DataSourceTransactionManager 数据源事务管理器 =========
* 1、如果程序中有多个数据源(javax.sql.DataSource),且没有设置首选 Bean (如@Primary标识),需要手动为 DataSourceTransactionManager 绑定需要的数据源
* 2、采用配置类的形式,将其添加到容器中,这样程序中可以直接 @Autowired 或者 @Resource 注入使用。
* 3、当然不在配置类中添加实例,直接在需要的地方 new DataSourceTransactionManager(DataSource dataSource) 也是可以的,同样放入目标数据源即可。
* 4、使用 Qualifier 指定对应名称的数据源进行注入
* <p>
* <p>
* ========= IOC容器(ApplicationContext)自动注入并使用 ApplicationContext =========
* 1、@Bean 添加实例时,方法中的参数可以获取容器中的任意实例,比如数据源-DataSource,IOC容器自身-ApplicationContext
* 2、@Bean 添加实例时,如果容器中同一类型存在多个实例,且没有标记优先级时,则需要使用 Qualifier 注解指定实例名称
*/
@Bean
public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource, ApplicationContext applicationContext) {
// 程序一启动就会执行本方法,然后从容器中获取实例,查询数据库数据
PhoneController phoneController1 = applicationContext.getBean(PhoneController.class);
List<Map<String, Object>> mapList2 = phoneController1.userList();
System.out.println(mapList2);
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
return transactionManager;
}
}
src/main/java/com/wmx/jdbc_template_app/config/AppConfig.java · 汪少棠/jdbc_template_app - Gitee.com
启动类 Main 方法中获取 IOC 容器
1、启动 Spring Boot 项目时,main 方法中 SpringApplication.run() 方法的返回值 ConfigurableApplicationContext 就是 ApplicationContext 的子接口,所以可以把 run() 方法返回的ApplicationContext 对象保存下来,随时使用。
@SpringBootApplication
public class JdbcTemplateAppApplication {
private static ApplicationContext applicationContext;
public static void main(String[] args) {
applicationContext = SpringApplication.run(JdbcTemplateAppApplication.class, args);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
System.out.println("========服务启动成功,IOC容器中实例如下:");
int count = 1;
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println((count++) + ":实例名称:" + beanDefinitionName + ",类型:" + applicationContext.getBean(beanDefinitionName).getClass());
}
}
}
WebApplicationContextUtils 工具类获取IOC容器
1、Spring 提供了工具类- WebApplicationContextUtils,可用于获取 ApplicationContext 对象。
/**
* http://localhost:8080/application/context2
* IOC 容器(BeanFactory & ApplicationContext) 实例通过内置 WebApplicationContextUtils 工具类获取
* <p>
* 获取 web 应用的根 WebApplicationContext(ApplicationContext的子接口)
* * WebApplicationContext getRequiredWebApplicationContext(ServletContext sc)
* * WebApplicationContext getWebApplicationContext(ServletContext sc)
* * WebApplicationContext findWebApplicationContext(ServletContext sc)
*
* @return
*/
@GetMapping("application/context2")
public Map<String, Object> applicationContext2(HttpServletRequest request) {
ApplicationContext webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
WebApplicationContextUtils.findWebApplicationContext()
PhoneController phoneController2 = (PhoneController) webApplicationContext.getBean("phoneController");
List<Map<String, Object>> mapList2 = phoneController2.userList();
Map<String, Object> dataMap = new HashMap<>(4);
dataMap.put("mapList2", mapList2);
return dataMap;
}
WebApplicationContext 获取项目全部请求URL
@RequestMapping(value = "/cucc/v2/getAllUrl")
@ResponseBody
public List<Map<String, Object>> getAllUrl2() {
RequestMappingHandlerMapping requestMapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
// 获取url与对应的类、方法信息
// RequestMappingInfo 中有请求头的url地址、请求方式等信息
// HandlerMethod 中有url所在的类、方法等信息;
Map<RequestMappingInfo, HandlerMethod> requestMap = requestMapping.getHandlerMethods();
List<Map<String, Object>> dataList = new ArrayList<>();
for (Map.Entry<RequestMappingInfo, HandlerMethod> requestEntry : requestMap.entrySet()) {
Map<String, Object> dataMap = new LinkedHashMap<>();
RequestMappingInfo requestMappingInfo = requestEntry.getKey();
HandlerMethod handlerMethod = requestEntry.getValue();
// 获取请求的url地址,因为一个方法可能对应多个url,所以是个集合;
// 会自动合成控制层接口上面的url前缀与方法上面的url后缀;
Set<String> patterns = requestMappingInfo.getPatternsCondition().getPatterns();
dataMap.put("requestUrl", patterns);
// 请求url对应的请求方式(如 GET、POST)
Set<RequestMethod> methods = requestMappingInfo.getMethodsCondition().getMethods();
List<String> typeList = new ArrayList<>();
for (RequestMethod requestMethod : methods) {
typeList.add(requestMethod.toString());
}
dataMap.put("requestType", typeList);
// 类名
dataMap.put("className", handlerMethod.getMethod().getDeclaringClass().getName());
// 方法名
dataMap.put("methodName", handlerMethod.getMethod().getName());
dataList.add(dataMap);
}
return dataList;
}
更多推荐
所有评论(0)