解读@NoArgsConstructor,@AllArgsConstructor,@RequiredArgsConstructor的区别及在springboot常用地方
作者:搏·梦
1. 先说结论
区别
- @NoArgsConstructor:生成无参的构造方法。
- @AllArgsConstructor:生成该类下全部属性的构造方法。
- @RequiredArgsConstructor:生成该类下被final修饰或者non-null字段生成一个构造方法。
场景
在springboot中,对于一个bean类,注入其他bean的时候,常见的是使用@Autowired,实际上也可以使用构造函数注入,这个时候就可以使用@AllArgsConstructor或者@RequiredArgsConstructor来代替。
2. 代码解析区别
@NoArgsConstructor 默认都知道。
若不知道怎么查看java反编译字节码内容,可以看一下:
Java如何进行反编译生成.java文件(javap、jad下载安装使用)
1. @AllArgsConstructor
@AllArgsConstructor public class demo { private String name; // 被final修饰 private final String age; @NonNull private String sex; }
根据反编译查看代码:
public class demo { // 默认 只要是该类下的字段,无论什么修饰,都会被参与构造 public demo(String name, String age, String sex) { if(sex == null) { throw new NullPointerException("sex is marked non-null but is null"); } else { this.name = name; this.age = age; this.sex = sex; return; } } private String name; private final String age; private String sex; }
2. @RequiredArgsConstructor
@RequiredArgsConstructor public class demo { private String name; // 被final修饰 private final String age; @NonNull private String sex; }
反编译代码:
public class demo { // 只构造了有final或者no-null修饰的字段 public demo(String age, String sex) { if(sex == null) { throw new NullPointerException("sex is marked non-null but is null"); } else { this.age = age; this.sex = sex; return; } } private String name; private final String age; private String sex; }
这是源码的英文解释:
3. 场景使用—代替@Autowired注入bean对象
1. @AllArgsConstructor
根据上面看反编译代码可以得出:只要是类里面字段,都会被加入到构造函数里面,不管被什么修饰。
例子:
@Component public class BeanTest1 { } @Component public class BeanTest2 { } @Component public class BeanTest3 { } @Component @AllArgsConstructor @ToString public class ConstructorDemo { // 注入三个bean对象,完全没有使用Autowired注解 private BeanTest1 beanTest1; @NonNull private BeanTest2 beanTest2; private final BeanTest3 beanTest3; } // 这只是个测试类 @Component public class ConstructorRunner implements ApplicationRunner { @Autowired ConstructorDemo ConstructorDemo; @Override public void run(ApplicationArguments args) throws Exception { System.out.println(ConstructorDemo); } }
完完全全可以注入bean对象。
2. @RequiredArgsConstructor
RequiredArgsConstructor:只会构造被final修饰或者no-null修饰的字段。
// 改成@RequiredArgsConstructor @Component @RequiredArgsConstructor @ToString public class ConstructorDemo { private BeanTest1 beanTest1; @NonNull private BeanTest2 beanTest2; private final BeanTest3 beanTest3; }
由图可以看出,没有被修饰final或者no-null的属性无法被注入,因此,建议使用@RequiredArgsConstructor的时候,对需要的字段加上final修饰。
注:强调 对需要的字段,为什么要强调,请看下面的例子:
3. @RequiredArgsConstructor与@AllArgsConstructor在注入bean上区别
根据上面两个例子,我们可以看出无论是那种方法都可以注入bean属性对象,只是@RequiredArgsConstructor 是针对有条件的,没有什么区别。
但如果是下面的需求呢:
在该类下,部分字段还需要使用@Value来注入值呢?
@Component @ToString public class ConstructorDemo { private BeanTest1 beanTest1; @NonNull private BeanTest2 beanTest2; private BeanTest3 beanTest3; @Value("${constructor.name:hello}") private String name; }
先思考一下:
一个bean如果使用构造函数进行bean属性注入,那么当然构造函数不能加上name。
因为加上,在创建ConstructorDemo该bean的时候,需要找类型为String,名字是name的bean对象,当然是不存在,必然会报错。
因此,当然不能使用@AllArgsConstructor了,只能使用@RequiredArgsConstructor
@AllArgsConstructor例子:
@Component @ToString @AllArgsConstructor public class ConstructorDemo { private BeanTest1 beanTest1; @NonNull private BeanTest2 beanTest2; private BeanTest3 beanTest3; @Value("${constructor.name:hello}") private String name; }
@RequiredArgsConstructor的例子
@Component @ToString @RequiredArgsConstructor public class ConstructorDemo { // 肯定为null,因为没有final或者no-null修饰 private BeanTest1 beanTest1; @NonNull private BeanTest2 beanTest2; private final BeanTest3 beanTest3; @Value("${constructor.name:hello}") private String name; }
4. 总结
上面只是举例了代替@Autowired的例子,实际上在json转化为对象,以及在spring中从配置文件读取配置使用@ConfigurationProperties以及@ConstructorBinding的时候,都可以使用构造函数赋值,都可以用到上面的两个@AllArgsConstructor、@RequiredArgsConstructor。
具体:只要记得,那些字段需要赋值,就把它列进构造方法的参数里面即可。
好了,以上仅为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。