实体类使用@Builder,导致@ConfigurationProperties注入属性失败

1. 前言

  1. 这里只是列出,可能需要补一下的知识点:
  2. 具体的yml文件字符串、List、Map的书写方式并使用@ConfigurationProperties注入配置类.
  3. 使用@Builder导致的无法创建无参构造方法

2. 场景

  1. @ConfigurationProperties注入属性,有两个很重要的条件:

    1. 该类必须是bean对象,即加了@Component注解。
    2. 该类必须得有set方法,即加@Setter注解。
  2. 偶然一次发现,当在该类加上@Builder注解,会直接导致无法属性注入。

  3. 重现
    正常情况下:

    @ToString
    @Setter
    @Component
    @ConfigurationProperties(prefix = "failed.test")
    public class demoFailedTest {
    
        private String username;
        private int age;
        private demoPerson demoPerson;
    }
    
    @Setter
    @ToString
    public class demoPerson {
        private String name;
        private String sex;
    }
    
    
    @Component("demoFailedTestRunner")
    public class demoRunner implements ApplicationRunner {
    
        @Autowired
        demoFailedTest demoFailedTest;
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            System.out.println(demoFailedTest);
        }
    }
    
    
    failed:
      test:
        user-name: failedTest
        age: 19
        demo-person:
          name: person
          sex: boy
    

    在这里插入图片描述

    异常情况:当在demoPerson类上加上@Builder注解:

    @Builder
    @Setter
    @ToString
    public class demoPerson {
        private String name;
        private String sex;
    }
    

    在这里插入图片描述
    一开始都惊了,本来就是符合条件的,demoPerson类上面有set方法,不应该注入不进来。

3. 解释

  1. 上面两张图片有个输出有个很细微的差异,一开始我也没有看出来,后来才反应过来了:

    第一个:
    demoFailedTest(username=failedTest, age=19, demoPerson=demoPerson(name=person, sex=boy))
    
    第二个:
    demoFailedTest(username=failedTest, age=19, demoPerson=null): demoPerson类上 加了@ToString
    讲道理,第二个报错不应该是:
    demoFailedTest(username=failedTest, age=19, demoPerson=demoPerson(name=null, sex=null))
    这样子才是真正注入不进来属性的结果。
    
    那么现在直接 demoPerson=null 代表 该demoPerson根本没有被创建对象!!!
    
  2. 后来详细去了解了@Builder注解的作用:
    详细:使用@Builder导致的无法创建无参构造方法
    简单说一下:就是如果你只是使用了@Builder则会导致 该类的没有无参构造函数,会有全参构造函数

  3. 重点:spring属性注入的时候,为什么要有set方法,显示它是使用set方法注入的,它又不能直接使用对象.set方法(),想必是使用了反射,那就必须得有对象吧,可得 spring肯定是先反射创建对象,是的,没错,spring默认是使用无参构造函数创建对象,再调用反射的set方法。

  4. 因此,如果加上@Builder注解,会没有无参构造函数方法,当然是没有办法创建对象了,因此才会出现 demoPerson=null的结果

4. 解决方法

  1. 具体@Builder的解决方法,上面链接里面有三种,我演示其中一种,即在该类上加上@AllArgsConstructor
    @NoArgsConstructor。

    @ToString
    @Setter
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class demoPerson {
        private String name;
        private String sex;
    
    }
    

    在这里插入图片描述

5. 思考

  1. 根据第四大点的解决方法,加上@AllArgsConstructor、@NoArgsConstructor即可,但有没有想过为什么要用@Builder方法,原因:
    1. builder创建对象方式很优雅,写的很简洁。
    2. 有没有一种可能,就是需求就是不想对外提供默认无参构造方法,或者全参构造方法,不想别人随便就可以new 对象出来了。
  2. 如果要满足第二点原因,显然现在是无法做到的,因为spring使用set方法注入,得有无参构造方法先创建对象,但是我们又不想提供无参构造方法,这不是矛盾吗?
  3. 再额外补充一个问题:如果这个Person类,我只想通过配置文件注入之后,永远不被修改,固然不能提供set方法,但是因为spring使用set方法注入属性,这不也是矛盾吗?
  4. 此时,突然脑子里面肯定会出现一个想法:为什么只会有set方法注入,不应该吧,set都可以,应该也可以有构造函数注入吧。
  5. 是的,下一篇文章:
    spring的构造函数注入属性@ConstructorBinding
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值