您的位置:首页 > 文旅 > 旅游 > 要对网页中各个元素_机票搜索量_获客软件排名前十名_每日新闻最新消息

要对网页中各个元素_机票搜索量_获客软件排名前十名_每日新闻最新消息

2025/1/20 5:59:05 来源:https://blog.csdn.net/qq_35971258/article/details/143133632  浏览:    关键词:要对网页中各个元素_机票搜索量_获客软件排名前十名_每日新闻最新消息
要对网页中各个元素_机票搜索量_获客软件排名前十名_每日新闻最新消息

文章目录

    • Spring 静态注入实际案例 Demo
    • 为什么这样写有时候 RemoteEBRpcInvoker.getEbFormIdUtil 是一个 NULL???
      • 原因1: 静态变量初始化顺序问题
      • 原因2: Spring 生命周期与静态字段
    • 解决方案:
      • 方法1:移除静态字段(违背了我的初衷)
      • 方法2:使用 @PostConstruct
      • 方法3: 使用 @Autowired 的静态方法
      • 方法4: 使用 ApplicationContext 获取 Bean
      • 方法5: 使用单例模式和手动注入
      • 方法6: 使用 @Lazy 懒加载
    • 总结
    • 推荐阅读文章

Spring 静态注入实际案例 Demo

有时候我们想将某个实例 Bean 封装成一个工具类,方便复用,也可以直接放到接口中定义为 default 方法。初衷就是这个。结果封装的工具类引发了 NPE 异常。造成线上重大事故😭😭😭

>>>>>>话不多说,直接看代码案例😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭😭:

为什么这样写有时候 RemoteEBRpcInvoker.getEbFormIdUtil 是一个 NULL???

@Component
public class RemoteEBRpcInvoker {private static final String DEFAULT_RPC_GROUP = "ebuilderform";private static PublishKitRuntimeUtil publishKitRuntimeUtil;private static GetEbFormIdUtil getEbFormIdUtil;@Autowiredpublic RemoteEBRpcInvoker(GetEbFormIdUtil getEbFormIdUtil,PublishKitRuntimeUtil publishKitRuntimeUtil) {RemoteEBRpcInvoker.getEbFormIdUtil = getEbFormIdUtil;RemoteEBRpcInvoker.publishKitRuntimeUtil = publishKitRuntimeUtil;}/*** 通过指定 appId 获取 RPC 服务实例** @param tClass 要构建的 RPC 服务类* @param appId  应用 ID* @param <T>    服务类的类型* @return 构建后的 RPC 服务实例*/public static <T> T newInstance(Class<T> tClass, Long appId) {Long appId = getEbFormIdUtil.getAppId(TagConstant.CS_APPID_TAG, tenantKey);return publishKitRuntimeUtil.buildRpcService(tClass, DEFAULT_RPC_GROUP, String.valueOf(appId));}}

就上面这段代码,在我们去调用 newInstance() 方法的时候,方法里面的 getEbFormIdUtil 竟然是个 NULL 对象。明显是我们这种写法 Spring 在静态注入的时候,直接没有引用成功。

所以在这种段代码中,“看似没问题”,实则 RemoteEBRpcInvoker.getEbFormIdUtil 可能为 null ,原因存在两种情况:

原因1: 静态变量初始化顺序问题

我正在使用静态变量 RemoteEBRpcInvoker.getEbFormIdUtilRemoteEBRpcInvoker.publishKitRuntimeUtil,而静态变量的生命周期和实例变量不同。@Autowired 注入的依赖通常在对象实例化时被注入,但静态变量属于类级别,不依赖于对象实例化。这可能导致在某些情况下(例如,依赖注入还未完成时)静态变量没有被正确赋值,导致它们为 null

原因2: Spring 生命周期与静态字段

Spring 依赖注入是基于对象实例的,静态变量不依赖于对象实例。@Autowired 只能保证在构造函数中注入实例变量,而不能确保静态变量的安全初始化。因为静态变量与类的生命周期绑定,而不是与实例的生命周期绑定,Spring 容器可能在静态字段初始化之前或之后管理类的生命周期,从而导致未能正确注入。

接下来是如何解决这个潜在问题方法介绍:

解决方案:

方法1:移除静态字段(违背了我的初衷)

避免将需要通过依赖注入获得的对象定义为静态字段,因为它们不依赖于实例。

你可以修改代码如下:

@Component
public class RemoteEBRpcInvoker {private static final String DEFAULT_RPC_GROUP = "ebuilderform";private PublishKitRuntimeUtil publishKitRuntimeUtil;private GetEbFormIdUtil getEbFormIdUtil;@Autowiredpublic RemoteEBRpcInvoker(GetEbFormIdUtil getEbFormIdUtil,PublishKitRuntimeUtil publishKitRuntimeUtil) {this.getEbFormIdUtil = getEbFormIdUtil;this.publishKitRuntimeUtil = publishKitRuntimeUtil;}
}

这个方法虽然行,但是违背了我的初衷,我需要封装一个工具类,那么就需要将方法弄成 static 状态方法。

方法2:使用 @PostConstruct

如果需要使用静态字段,你可以利用 @PostConstruct 注解,在依赖注入完成后手动初始化静态变量。

@Component
public class RemoteEBRpcInvoker {private static final String DEFAULT_RPC_GROUP = "ebuilderform";private static PublishKitRuntimeUtil publishKitRuntimeUtil;private static GetEbFormIdUtil getEbFormIdUtil;@Autowiredpublic RemoteEBRpcInvoker(GetEbFormIdUtil getEbFormIdUtil,PublishKitRuntimeUtil publishKitRuntimeUtil) {this.getEbFormIdUtil = getEbFormIdUtil;this.publishKitRuntimeUtil = publishKitRuntimeUtil;}@PostConstructpublic void init() {RemoteEBRpcInvoker.getEbFormIdUtil = this.getEbFormIdUtil;RemoteEBRpcInvoker.publishKitRuntimeUtil = this.publishKitRuntimeUtil;}
}

这种方法可以确保在依赖注入完成后,静态变量被正确赋值。

除了我之前提到的解决方案之外,还有一些其他方法可以避免静态字段注入问题,并确保你能够在 Spring 环境中正确地使用静态字段。以下是其他几种可能的方法:

方法3: 使用 @Autowired 的静态方法

你可以通过编写一个静态的 setter 方法来为静态变量注入依赖。Spring 允许通过 @Autowired 注解静态方法来完成依赖注入。这种方式不会依赖于实例,因此更加符合静态变量的使用场景。

@Component
public class RemoteEBRpcInvoker {private static final String DEFAULT_RPC_GROUP = "ebuilderform";private static PublishKitRuntimeUtil publishKitRuntimeUtil;private static GetEbFormIdUtil getEbFormIdUtil;@Autowiredpublic static void setPublishKitRuntimeUtil(PublishKitRuntimeUtil publishKitRuntimeUtil) {RemoteEBRpcInvoker.publishKitRuntimeUtil = publishKitRuntimeUtil;}@Autowiredpublic static void setGetEbFormIdUtil(GetEbFormIdUtil getEbFormIdUtil) {RemoteEBRpcInvoker.getEbFormIdUtil = getEbFormIdUtil;}
}

这种方法通过静态的 setter 方法来完成静态变量的注入,确保它们在类加载时能被正确初始化。

方法4: 使用 ApplicationContext 获取 Bean

另一种方法是使用 Spring 的 ApplicationContext 来手动获取所需的 Bean。这种方法可以在静态上下文中安全地使用依赖注入。

你可以通过以下方式将 ApplicationContext 注入,并在需要时手动获取依赖。

@Component
public class RemoteEBRpcInvoker implements ApplicationContextAware {private static final String DEFAULT_RPC_GROUP = "ebuilderform";private static ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {RemoteEBRpcInvoker.applicationContext = applicationContext;}public static GetEbFormIdUtil getGetEbFormIdUtil() {return applicationContext.getBean(GetEbFormIdUtil.class);}public static PublishKitRuntimeUtil getPublishKitRuntimeUtil() {return applicationContext.getBean(PublishKitRuntimeUtil.class);}
}

在这种方法中,ApplicationContext 被注入到静态字段 applicationContext 中,并通过静态方法从上下文中获取所需的 Bean。这避免了直接使用 @Autowired 注解静态字段的问题。

方法5: 使用单例模式和手动注入

如果你确实需要使用静态方法或静态字段,也可以考虑使用单例模式来管理这些依赖。在这种情况下,你可以手动注入依赖,并在静态上下文中访问它们。

@Component
public class RemoteEBRpcInvoker {private static final String DEFAULT_RPC_GROUP = "ebuilderform";private static RemoteEBRpcInvoker instance;private PublishKitRuntimeUtil publishKitRuntimeUtil;private GetEbFormIdUtil getEbFormIdUtil;@Autowiredpublic RemoteEBRpcInvoker(GetEbFormIdUtil getEbFormIdUtil,PublishKitRuntimeUtil publishKitRuntimeUtil) {this.getEbFormIdUtil = getEbFormIdUtil;this.publishKitRuntimeUtil = publishKitRuntimeUtil;instance = this;}public static RemoteEBRpcInvoker getInstance() {return instance;}public GetEbFormIdUtil getGetEbFormIdUtil() {return this.getEbFormIdUtil;}public PublishKitRuntimeUtil getPublishKitRuntimeUtil() {return this.publishKitRuntimeUtil;}
}

这种方式通过一个静态的 instance 来存储当前对象实例,从而可以在静态上下文中访问非静态字段和方法。虽然这并不是典型的 Spring 注入方式,但它可以让你在需要使用静态字段时仍然能访问 Spring 管理的依赖。

方法6: 使用 @Lazy 懒加载

如果某些依赖可能在初始化时无法立即注入,或者你希望推迟静态字段的初始化,可以使用 @Lazy 注解,使依赖注入变为懒加载模式,这样可以确保当依赖确实需要时才会初始化。

@Component
public class RemoteEBRpcInvoker {private static final String DEFAULT_RPC_GROUP = "ebuilderform";private static PublishKitRuntimeUtil publishKitRuntimeUtil;private static GetEbFormIdUtil getEbFormIdUtil;@Autowired@Lazypublic RemoteEBRpcInvoker(GetEbFormIdUtil getEbFormIdUtil,PublishKitRuntimeUtil publishKitRuntimeUtil) {RemoteEBRpcInvoker.getEbFormIdUtil = getEbFormIdUtil;RemoteEBRpcInvoker.publishKitRuntimeUtil = publishKitRuntimeUtil;}
}

懒加载会推迟对依赖的初始化,直到第一次实际使用时才进行初始化。这种方式可以帮助解决静态字段在不适当的时间被初始化的问题。


总结

如果遇到以上问题,可以通过以下几种方式解决静态字段注入问题:

  1. 避免静态字段,使用实例字段(推荐)
  2. 使用 @PostConstruct 注解初始化
  3. 使用 静态 setter 方法 来注入静态依赖
  4. 使用 ApplicationContext 手动获取依赖
  5. 通过 单例模式 访问非静态依赖
  6. 使用 @Lazy 注解 懒加载依赖

以上每种方法都有其适用场景,具体选择可以根据项目的需求和设计模式来决定。ε=(´ο`*)))唉,希望此文可以帮助大家踩坑时避坑吧。。。

推荐阅读文章

  • 使用 Spring 框架构建 MVC 应用程序:初学者教程
  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误
  • 如何理解应用 Java 多线程与并发编程?
  • Java Spring 中常用的 @PostConstruct 注解使用总结
  • 线程 vs 虚拟线程:深入理解及区别
  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别
  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!
  • “打破重复代码的魔咒:使用 Function 接口在 Java 8 中实现优雅重构!”
  • Java 中消除 If-else 技巧总结
  • 线程池的核心参数配置(仅供参考)
  • 【人工智能】聊聊Transformer,深度学习的一股清流(13)
  • Java 枚举的几个常用技巧,你可以试着用用
  • 如何理解线程安全这个概念?
  • 理解 Java 桥接方法
  • Spring 整合嵌入式 Tomcat 容器
  • Tomcat 如何加载 SpringMVC 组件

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com