首页 > 其他分享 >NullPointerException—配置属性为null

NullPointerException—配置属性为null

时间:2024-10-23 08:50:38浏览次数:3  
标签:初始化 AliOssUtil Spring aliOssProperties AliOssProperties Bean null NullPointerExc

1. 问题描述

空指针异常,获取属性配置类AliOssProperties中的endpoint属性时,为空。

配置文件中正确配置了相关的属性,并且AliOssProperties上加了@ConfigurationProperties,启动类上通过@EnableConfigurationProperties(AliOssProperties.class)启用了配置属性支持。

Error starting ApplicationContext. 
To display the conditions report re-run your application with 'debug' enabled.
Failed to instantiate [com.cyt.utils.AliOssUtil]: 
Constructor threw exception; 
nested exception is java.lang.NullPointerException: 
Cannot invoke "com.cyt.properties.AliOssProperties.getEndpoint()" 
because "this.aliOssProperties" is null

2. 问题分析

原因是在 @Autowired 注入 AliOssProperties 时,注入发生在 Spring 容器初始化的过程中,而 endpointaccessKeyId 等这些字段是在 aliOssProperties 注入之前初始化的,所以它们在被注入之前仍然是 null

@Autowired
private AliOssProperties aliOssProperties;

private String endpoint = aliOssProperties.getEndpoint();  // 这里可能会导致 NPE
private String accessKeyId = aliOssProperties.getAccessKeyId();
private String accessKeySecret = aliOssProperties.getAccessKeySecret();
private String bucketName = aliOssProperties.getBucketName();

这些字段的赋值依赖于 aliOssProperties,但是由于 aliOssProperties 还未完成注入,所以当 Spring 初始化这些字段时,aliOssProperties 仍然是 null,因此会导致 NullPointerException

3. 知识扩展

在 Spring 中,@Autowired 注解和属性的初始化顺序是由 Java 类的生命周期以及 Spring 容器的管理流程决定的。以下是注入和属性初始化的先后过程,解释为什么在使用 @Autowired 注入时,直接给属性赋值可能导致 NullPointerException

3.1  Java 类的加载与初始化顺序

Java 类的加载和初始化是 JVM 管理的一个流程,通常包括以下几个步骤:

  1. 加载类(Class Loading):JVM 会加载类的字节码到内存中。
  2. 链接类(Class Linking):JVM 会对类的静态部分进行解析和验证。
  3. 类初始化(Class Initialization)
    • 静态变量初始化:静态变量初始化是类加载的一部分,优先级最高。
    • 实例变量初始化:接下来是非静态实例变量的初始化。
    • 构造器初始化:最后执行构造方法,完成类的实例化。

3.2 Spring Bean 的初始化顺序

在 Spring 中,Bean 的生命周期由 Spring 容器管理,Bean 初始化时会经历以下几个重要步骤:

  1. Bean 实例化(Instantiation):Spring 容器首先根据配置文件或注解扫描生成类的实例,即通过无参构造函数创建对象(等同于 new 操作)。

  2. 依赖注入(Dependency Injection):此时,Spring 会为类中的 @Autowired@Value 注解的字段注入依赖项。比如,将 AliOssProperties 对象注入到 AliOssUtil 类中。

  3. 初始化回调(Initialization Callback):如果类实现了 InitializingBean 接口或使用了 @PostConstruct 注解,Spring 会在依赖注入完成后调用相关方法进行初始化。

  4. Bean 可用:完成依赖注入和初始化后,Bean 才真正可以被使用。

3.3 发生 NullPointerException 的原因

  1. Bean 实例化:Spring 首先实例化 AliOssUtil 类,也就是执行 new AliOssUtil() 操作。此时,Spring 容器还没有为 aliOssProperties 注入值。

  2. 属性初始化:在实例化过程中,类中的实例变量会被初始化。此时,Java 会尝试为 endpointaccessKeyId 等字段赋值。这些字段是基于 aliOssProperties 进行初始化的,而 aliOssProperties 还没有被注入,因此它的值是 null。调用 aliOssProperties.getEndpoint() 就会抛出 NullPointerException

  3. 依赖注入:实例化和属性初始化完成后,Spring 才会执行依赖注入操作,将 aliOssProperties 注入到 AliOssUtil 类中。这时 aliOssProperties 才不再是 null,但是已经错过了在声明时直接赋值的时机。

4. 解决方案

4.1 在方法中使用

不要在属性声明时使用 aliOssProperties,而是在方法中延迟使用它。

@Component
@Slf4j
public class AliOssUtil {

    @Autowired
    private AliOssProperties aliOssProperties;

    public String upload(byte[] bytes, String objectName) {
        // 在使用时再获取 aliOssProperties 的值,确保此时它已经注入完成
        String endpoint = aliOssProperties.getEndpoint();
        String accessKeyId = aliOssProperties.getAccessKeyId();
        String accessKeySecret = aliOssProperties.getAccessKeySecret();
        String bucketName = aliOssProperties.getBucketName();

        // 上传逻辑...
    }
}

4.2 手动配置 AliOssUtil的Bean对象

4.2.1 实现

通过 Java Config 类 使用 @Bean 注解手动创建 AliOssUtil 实例,而不是通过默认的 Spring 容器自动扫描和注入。它解决了依赖注入和属性初始化顺序的问题,因为显式地将AliOssProperties 的属性传递给 AliOssUtil。

/**
 * 配置类,用于创建AliOssUtil对象
 */
@Configuration
@Slf4j
public class OssConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties){
        log.info("开始创建阿里云文件上传工具类对象:{}",aliOssProperties);
        return new AliOssUtil(aliOssProperties.getEndpoint(),
                aliOssProperties.getAccessKeyId(),
                aliOssProperties.getAccessKeySecret(),
                aliOssProperties.getBucketName());
    }
}

@ConditionalOnMissingBean 表示当 Spring 容器中不存在 AliOssUtil 类型的 Bean 时,才会创建这个 Bean。这样可以避免重复创建 Bean 的问题,防止冲突。这对于大型项目特别有用,因为不同的模块可能会有不同的配置来源,如果某个模块已经定义了 AliOssUtil,这个配置类就不会重复创建。

4.2.2 分析

由于 Spring 的依赖注入机制,Spring 会按照依赖顺序来解析每个 Bean。当 AliOssUtil 依赖于 AliOssProperties 时,Spring 会确保在创建 AliOssUtil 实例之前,AliOssProperties 已经完成初始化。因此:

  • 当 Spring 看到 aliOssUtil 方法的参数是 AliOssProperties,它会先去查找并创建(如果尚未创建)一个 AliOssProperties 实例。
  • 之后,Spring 会将这个 AliOssProperties 实例传递给 aliOssUtil 方法。
  • 由于 AliOssProperties 已经正确初始化并注入,AliOssUtil 的构造函数可以安全地使用这些属性进行初始化。

5. 总结

  • Spring 的依赖注入是在 Bean 实例化后进行的,因此如果在 Bean 实例化时就使用未注入的依赖项(比如 @Autowired 的属性),可能会导致 NullPointerException
  • 为了解决这个问题,可以延迟对依赖项的使用(即在方法中使用),或者手动管理Bean对象。

标签:初始化,AliOssUtil,Spring,aliOssProperties,AliOssProperties,Bean,null,NullPointerExc
From: https://blog.csdn.net/qq_46637011/article/details/143166085

相关文章

  • Spring Boot 依赖注入为 null 问题
    目录问题省流代码复现TestServiceTestAspectTestController源码分析AbstractAutoProxyCreatorCglibAopProxyEnhancer问题工作中,在负责的模块里使用@DubboService注解注册了一个dubbo接口,给定时任务模块去调用。在自我调试阶段,需要在本地自己验证一下接口的功......
  • script crossorigin 属性
    来源:https://juejin.cn/post/6969825311361859598 <scriptsrc="xxxx"crossorigin="anonymous"></script>有时候会看到这样的代码,设置了crossorigin="anonymous"这个属性,个人认知里面是跟跨域有关系的。但是仔细一想,本来script标签就是可以跨域请求资源的,那crossorigin="......
  • HarmonyOS Next 动画大全01-属性动画
    HarmonyOSNext动画大全01-属性动画介绍动画,指的是我们应用中的元素,在发生位置、大小、颜色、形状等属性变化时,可以产出一个缓慢变化的效果。让用户的焦点一直跟随在应用的行动中,增加用户使用的体验和让用户知道当前的行动进度。如下图的就是有无动画的效果对比:(图片来自华为......
  • 软件架构的10个质量属性
    原文链接:软件架构的10个质量属性–每天进步一点点一般地,对于软件系统的需求而言,分为两类:功能性需求和非功能性需求。软件系统的架构设计既要满足软件的功能性需求,还要满足软件的非功能性需求。特别地,系统架构对软件非功能性需求的支撑成为架构的质量属性。本文描述了软件的10......
  • 【Vue】Vue3.0(十三)中标签属性ref(加在普通标签上、加在组件标签上)、局部样式
    上篇文章:【Vue】Vue3.0(十二)、watchEffect和watch的区别及使用......
  • ## text 文本属性
    text文本属性<!--设置文本的装饰线-->常见取值text-decoration:none没有任何装饰线(可用于去除a标签默认的下划线)text-decoration:underline下划线text-decoration:overline上划线text-decoration:line-through中划线删除线text-decoration/*无装饰线*/......
  • ## font 文体属性
    文字大小font-size:设置字体样式在浏览器渲染的时候会先考虑当前操作系统字体库是否具备设置的字体,当不支持这个字体的时候会用浏览器默认的字体显示,在设置font-family时最好多设置几个备用字体可以通过网络方式直接下载字体@font-face指定的可以直接下载字体.font-f......
  • jar包运行报错1.无主属性清单 2.外部Jar包未导入 3.Data Source url报错解决 4.端口占
    相信大家mvnpackage打包成jar包后放到服务器上面运行后遇到一些很头疼的问题,怎么按照百度、gpt、csdn上面的博客修改就是成功不了但是!今天!博主带着自己尝试多次的血泪经验为大家解答以上三大问题!接下来以“代码+解析”的方式解析大家的问题一、无主属性问题报错如下图这......
  • WPF中Grid、StackPanel、Canvas、WrapPanel常用属性
    Grid常用属性Grid控件在WPF中非常强大,它提供了多种属性来定义行和列的布局。以下是一些常用的Grid属性:RowDefinitions和ColumnDefinitions:Grid 控件使用 RowDefinitions 和 ColumnDefinitions 来定义行和列的集合。每个 RowDefinition 和 ColumnDefinition......
  • webAPI中的排他思想、自定义属性操作、节点操作(配大量案例练习)
    一、排他操作1.排他思想如果有同一组元素,我们想要某一个元素实现某种样式,需要用到循环的排他思想算法:1.所有的元素全部清除样式2.给当前的元素设置样式注意顺序能不能颠倒,首先清除全部样式,再设置自己当前的样式<!DOCTYPEhtml><htmllang="en"><head><meta......