Hutool中SpringUtil中的一个坑-所有路由消失
问题场景
Spring boot 2.7.18
使用Hutool文档中使用方法
@ComponentScan(basePackages={"cn.hutool.extra.spring"})
@Import(cn.hutool.extra.spring.SpringUtil.class)
在主入口定义,会导致路由全部消失,接口访问404。
解决方案
使用提供的@EnableSpringUtil
注解或者新建个配置类,将两个注解放到上面。
原因分析
ComponentScan
注解 与 @Import
注解
@ComponentScan
用于自动检测和注册带有特定注解的类为bean。这些注解通常包括但不限于 @Component
, @Service
, @Repository
, 和 @Controller
。当一个配置类上使用了 @ComponentScan
,Spring会扫描指定的包及其子包,并将所有带有上述注解的类作为bean注册到IoC容器中。
@ComponentScan
主要用于自动发现和注册组件@Impoert
适用于导入特定的配置类和静态bean定义,便于模块化配置
怀疑是@SpringApplication
中的@ComponentScan
同主入口的@ComponetScan
相冲突
BeanFactoryPostProcessor
允许开发者在Spring IoC容器初始化之前对BeanFactory进行修改,是最早要执行的方法。该接口只有一个方法需要实现
public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
这个函数允许访问并修改BeanFactory的内容,这个方法调用发生在所有bean实例化之前,可以进行配置。
ApplicationContextAware
使一个类能够获得整个Spring应用上下文(ApplicationContext
)的引用。通常,当一个类实现了ApplicationContextAware
接口后,Spring容器会在初始化该类的实例时自动调用一个回调方法,将当前的ApplicationContext
实例注入给该类。
SpringUtil的代码
通过实现上面两个BeanFactoryPostProcessor
和ApplicationContextAware
的接口,可以实现Util方法,不用实例化,直接调用静态方法
@Component
public class SpringUtil implements BeanFactoryPostProcessor, ApplicationContextAware {/*** "@PostConstruct"注解标记的类中,由于ApplicationContext还未加载,导致空指针<br>* 因此实现BeanFactoryPostProcessor注入ConfigurableListableBeanFactory实现bean的操作*/private static ConfigurableListableBeanFactory beanFactory;/*** Spring应用上下文环境*/private static ApplicationContext applicationContext;@SuppressWarnings("NullableProblems")@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {SpringUtil.beanFactory = beanFactory;}@SuppressWarnings("NullableProblems")@Overridepublic void setApplicationContext(ApplicationContext applicationContext) {SpringUtil.applicationContext = applicationContext;}/*** 获取{@link ApplicationContext}** @return {@link ApplicationContext}*/public static ApplicationContext getApplicationContext() {return applicationContext;}/*** 获取{@link ListableBeanFactory},可能为{@link ConfigurableListableBeanFactory} 或 {@link ApplicationContextAware}** @return {@link ListableBeanFactory}* @since 5.7.0*/public static ListableBeanFactory getBeanFactory() {final ListableBeanFactory factory = null == beanFactory ? applicationContext : beanFactory;if (null == factory) {throw new UtilException("No ConfigurableListableBeanFactory or ApplicationContext injected, maybe not in the Spring environment?");}return factory;}/*** 获取{@link ConfigurableListableBeanFactory}** @return {@link ConfigurableListableBeanFactory}* @throws UtilException 当上下文非ConfigurableListableBeanFactory抛出异常* @since 5.7.7*/public static ConfigurableListableBeanFactory getConfigurableBeanFactory() throws UtilException {final ConfigurableListableBeanFactory factory;if (null != beanFactory) {factory = beanFactory;} else if (applicationContext instanceof ConfigurableApplicationContext) {factory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();} else {throw new UtilException("No ConfigurableListableBeanFactory from context!");}return factory;}
在Bean注册时,已经完成了BeanFactory的实例化,可以直接调用getBean等方法了。