一、背景
在 controller 层想使用一个静态工具,这个静态工具要使用其它组件。
我们经常要使用 @Autowired 注解注入 Service 或者 Mapper 接口,在 service 层中注入其它的service 接口或者 mapper 接口都是可以的,但是如果我们要在我们自己封装的 Utils 工具类中使用 @Autowired 注解注入 Service 或者 Mapper 接口,直接注入是不可能的,因为 Utils 使用了静态的方法,我们是无法直接使用非静态接口的,当我们遇到这样的问题,我们就要想办法解决了。
二、错误示范:在静态字段上注入
1、Controller
@PostMapping("/test")public String test() {WelcomeUtil.welcome();return "test utils success!";}
2、工具类
@Component
public class WelcomeUtil {@Autowiredprivate static Hello hello;public static void welcome() {hello.sayHello();}}
3、引入的组件
@Component
public class Hello {public void sayHello() {System.out.println("Hello");}}
4、测试接口
localhost:8080/testUtils/test
运行结果:
java.lang.NullPointerException: nullat com.example.demo.utils.WelcomeUtil.welcome(WelcomeUtil.java:18) ~[classes/:na]at com.example.demo.controller.HelloController.test(HelloController.java:21) ~[classes/:na]
总结:在工具类中直接注入,在调用工具类方法时会报空指针异常,需要设置 bean 的注入。
三、方案二
其余代码与上边相同
1、工具类
@Component
public class WelcomeUtil {private static Hello hello;public static void welcome() {hello.sayHello();}@Autowiredpublic void setHello(Hello hello) {WelcomeUtil.hello = hello;}}
2、测试接口
localhost:8080/testUtils/test
运行结果:
"test utils success!"
四、方案三
1、工具类(使用 @PostConstruct 注解)
@Component
public class WelcomeUtil {@Autowiredprivate Hello hello;private static WelcomeUtil welcomeUtil;@PostConstructpublic void init() {// 可以加载多个组件welcomeUtil = this;welcomeUtil.hello = this.hello;}public static void welcome() {welcomeUtil.hello.sayHello();}}
- 将 WelcomeUtil 上添加 @Component 声明其为 bean 组件。
- 使用 @Autowired 注入启动类
- 在 WelcomeUtil 声明一个 静态的私有变量 private static WelcomeUtil welcomeUtil;
- 添加共有的 init 方法,并用 @PostConstruct 声明在项目启动的时候进行执行该方法,也可以理解为在 spring 容器初始化的时候执行该方法。
想要深入了解该注解的,可以看我这篇文章:【Java基础】@PostConstruct 和 @PreDestroy 注解的使用
2、测试接口
localhost:8080/testUtils/test
运行结果:
"test utils success!"
五、方案四
1、ApplicationContextHolderUtil 工具类(范例统一写法,基本没有什么变化)
/*** 获取 spring 容器,以访问容器中定义的其它 bean*/
@Component
@Slf4j
public class ApplicationContextHolderUtil implements ApplicationContextAware {// Spring 应用上下文环境private static ApplicationContext applicationContext;/*** 重写接口的方法,该方法的参数为框架自动加载的IOC容器对象* 该方法在启动项目的时候会自动执行,前提是该类上有IOC相关注解,例如@Component* @param applicationContext ioc容器* @throws BeansException e*/@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {// 将框架加载的ioc赋值给全局静态iocApplicationContextHolderUtil.applicationContext = applicationContext;log.info("==================ApplicationContext加载成功==================");}//获取applicationContextpublic static ApplicationContext getApplicationContext() {return applicationContext;}/*** 获取对象* @param name* @return Object 一个以所给名字注册的 bean 的实例(service 注解方式,自动生成以首字母小写的类名为 bean name)*/public static Object getBean(String name){return getApplicationContext().getBean(name);}//通过class获取Bean.public static <T> T getBean(Class<T> clazz){return getApplicationContext().getBean(clazz);}//通过name,以及Clazz返回指定的Beanpublic static <T> T getBean(String name,Class<T> clazz){return getApplicationContext().getBean(name, clazz);}
}
2、工具类
@Component
public class WelcomeUtil {public static void welcome() {ApplicationContextHolderUtil.getApplicationContext().getBean(Hello.class).sayHello();}}
3、测试接口
localhost:8080/testUtils/test
运行结果:
"test utils success!"
六、参考文档
Spring boot遇坑之工具类中注入 bean
SpringBoot--将组件注入到静态工具类--方法/实例