一、概述
主要作用:
- 获取IOC容器里面BEAN对象
- 注册和注销BEAN
- 获取应该上下文
二、代码详解
hutool 包中的 SpringUtil 实现了2个类:
- BeanFactoryPostProcessor: Bean工厂的处理器,可配置的Bean列表ConfigurableListableBeanFactory ,设置到 beanFactory 工厂中
- ApplicationContextAware : 上下文感知,重写获取上下文方法,setApplicationContext
package cn.hutool.extra.spring;
/**
* Spring(Spring boot)工具封装,包括:
*
* <ol>
* <li>Spring IOC容器中的bean对象获取</li>
* <li>注册和注销Bean</li>
* </ol>
*
* @author loolly
* @since 5.1.0
*/
@Component
public class SpringUtil implements BeanFactoryPostProcessor, ApplicationContextAware {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
SpringUtil.beanFactory = beanFactory;
}
@SuppressWarnings("NullableProblems")
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringUtil.applicationContext = applicationContext;
}
SpringUtils 工具类则继承了hutools方法:
@Component
public final class SpringUtils extends SpringUtil {
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name) {
return getBeanFactory().containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。
* 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
*
* @param name
* @return boolean
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().isSingleton(name);
}
/**
* @param name
* @return Class 注册对象的类型
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
*
* @param name
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getAliases(name);
}
/**
* 获取aop代理对象
*
* @param invoker
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getAopProxy(T invoker) {
return (T) AopContext.currentProxy();
}
/**
* 获取spring上下文
*/
public static ApplicationContext context() {
return getApplicationContext();
}
}
三、测试常用的方法
1-SpringUtils.getBean
@GetMapping("test1")
public void test(){
TestSpringUtilsController bean = SpringUtils.getBean(TestSpringUtilsController.class);
bean.test1();
}
public void test1(){
log.info("test1被调用");
}
结果:test1被调用
2024-08-11 15:26:19 [XNIO-1 task-2] INFO c.r.d.c.TestSpringUtilsController
- test1被调用
扩展map类型获取:
@Bean("myMap")
public Map<String, Object> test8(){
Map<String, Object> map = new HashMap<>();
map.put("test8","test8Value");
return map;
}
@GetMapping("test9")
public void test9(){
Map<String, Object> myMap = SpringUtils.getBean("myMap");
log.info("myMap:{}",myMap);
//根据bean类型获取
Map<String, Object> en = SpringUtils.getBean(new TypeReference<Map<String, Object>>() {});
log.info("bean:{}",myMap);
}
结果:
2024-08-11 16:59:36 [XNIO-1 task-2] INFO c.r.d.c.TestSpringUtilsController
- myMap:{test8=test8Value}
2024-08-11 16:59:36 [XNIO-1 task-2] INFO c.r.d.c.TestSpringUtilsController
- bean:{test8=test8Value}
2-SpringUtils.getBeansOfType:获取类下注册的BEAN
如代码 TestDemo 类,通过@Bean注解注册2个bean
@GetMapping("test2")
public void test2(){
Map<String, TestDemo> beansOfType = SpringUtils.getBeansOfType(TestDemo.class);
for (String s :beansOfType.keySet()){
log.info("key:{}",s);
log.info("bean:{}",beansOfType.get(s));
}
}
@Bean("diyName")
public TestDemo testDemoFun(){
return new TestDemo();
}
@Bean("diyName1")
public TestDemo testDemoFun1(){
return new TestDemo();
}
执行结果:
2024-08-11 15:49:14 [XNIO-1 task-2] INFO c.r.d.c.TestSpringUtilsController
- key:diyName
2024-08-11 15:49:14 [XNIO-1 task-2] INFO c.r.d.c.TestSpringUtilsController
- bean:TestDemo(id=null, deptId=null, userId=null, orderNum=null, testKey=null, value=null, version=null, delFlag=null)
3-注册、注销bean
@GetMapping("test3")
public void test3(){
TestDemo testDemo = new TestDemo();
testDemo.setId(1L);
//注册
SpringUtils.registerBean("testDemo", testDemo);
Object bean1 = SpringUtils.getBean("testDemo");
log.info("testDemo:{}",bean1);
//注销
SpringUtils.unregisterBean("testDemo");
try {
Object bean2 = SpringUtils.getBean("testDemo");
log.info("testDemo:{}",bean2);
}catch (Exception e){
log.error("未获取到bean");
}
}
执行结果:
注册bean后,打印成功。注销之后打印未获取到bean
2024-08-11 16:06:05 [XNIO-1 task-2] INFO c.r.d.c.TestSpringUtilsController
- testDemo:TestDemo(id=1, deptId=null, userId=null, orderNum=null, testKey=null, value=null, version=null, delFlag=null)
2024-08-11 16:06:05 [XNIO-1 task-2] ERROR c.r.d.c.TestSpringUtilsController
- 未获取到bean
4-其他常用方法:获取类注册bean名称、是否单例等
@Bean("diyName")
public TestDemo testDemoFun(){
return new TestDemo();
}
@Bean("diyName1")
public TestDemo testDemoFun1(){
return new TestDemo();
}
@GetMapping("test4")
public void test4(){
try {
String[] beanNamesForType = SpringUtils.getBeanNamesForType(TestDemo.class);
log.info("beanNamesForType:{}",beanNamesForType);
//是否包含bean
boolean testDemo = SpringUtils.containsBean("diyName");
log.info("containsBean:{}",testDemo);
//是否单例
boolean isSingleton = SpringUtils.isSingleton("diyName1");
log.info("isSingleton:{}",testDemo);
//获取应用名称
String applicationName = SpringUtils.getApplicationName();
log.info("applicationName:{}",applicationName);
}catch (Exception e){
log.error("未获取到bean");
}
}
打印结果:
2024-08-11 16:21:59 [XNIO-1 task-2] INFO c.r.d.c.TestSpringUtilsController
- beanNamesForType:diyName
2024-08-11 16:21:59 [XNIO-1 task-2] INFO c.r.d.c.TestSpringUtilsController
- containsBean:true
2024-08-11 16:21:59 [XNIO-1 task-2] INFO c.r.d.c.TestSpringUtilsController
- isSingleton:true
2024-08-11 16:21:59 [XNIO-1 task-2] INFO c.r.d.c.TestSpringUtilsController
- applicationName:RuoYi-Vue-Plus
5-SpringUtils.getProperty:获取yml配置项
比如我们打印配置文件中的端口号
@GetMapping("test5")
public void test5(){
try {
String property = SpringUtils.getProperty("server.port");
log.info("property:{}",property);
}catch (Exception e){
log.error("未获取到bean");
}
}
2024-08-11 16:30:45 [XNIO-1 task-1] INFO c.r.d.c.TestSpringUtilsController
- property:8080
6-获取代理对象
比如这种写法每次都会直接进入test7方法,而不会去命中缓存
@GetMapping("test6")
public void test6(){
String s = test7();
log.info("test7:{}",s);
}
@Cacheable(value = "testCache",key = "key")
public String test7(){
log.info("直接进入test7方法");
return "ss";
}
每次请求都不会走上面缓存注解,直接进入test7方法。说明代理对象切面未生效
2024-08-11 16:40:14 [XNIO-1 task-1] INFO c.r.d.c.TestSpringUtilsController
- 直接进入test7方法
2024-08-11 16:40:14 [XNIO-1 task-1] INFO c.r.d.c.TestSpringUtilsController
- test7:ss
2024-08-11 16:40:16 [XNIO-1 task-1] INFO c.r.d.c.TestSpringUtilsController
- 直接进入test7方法
2024-08-11 16:40:16 [XNIO-1 task-1] INFO c.r.d.c.TestSpringUtilsController
- test7:ss
2024-08-11 16:40:17 [XNIO-1 task-1] INFO c.r.d.c.TestSpringUtilsController
- 直接进入test7方法
2024-08-11 16:40:17 [XNIO-1 task-1] INFO c.r.d.c.TestSpringUtilsController
- test7:ss
解决办法:
@GetMapping("test6")
public void test6(){
//String s = test7();
String s = SpringUtils.getAopProxy(this).test7();
log.info("test7:{}",s);
}
@Cacheable(value = "testCache",key = "key")
public String test7(){
log.info("直接进入test7方法");
return "ss";
}
这样第一次请求直接调用test7,后面请求就会走缓存不会调用test7。 @Cacheable注解生效
2024-08-11 16:48:24 [XNIO-1 task-2] INFO c.r.d.c.TestSpringUtilsController
- 直接进入test7方法
2024-08-11 16:48:24 [XNIO-1 task-2] INFO c.r.d.c.TestSpringUtilsController
- test7:ss
2024-08-11 16:48:27 [XNIO-1 task-2] INFO c.r.d.c.TestSpringUtilsController
- test7:ss