spring系列之——使用@Autowired注解,不建议基于字段的依赖注入
介绍使用@Autowired注解基于字段的依赖注入时,IDEA会出现弱警告,如下:思考:为什么不推荐使用,这种方式是不是有更好的替代方案。依赖注入方式依赖注入有三种方式:基于字段注入基于构造器注入基于set方法注入1、基于字段注入@Servicepublic class EmployeeServiceImpl implements EmployeeService {@Autowiredprivat
·
介绍
使用@Autowired注解基于字段的依赖注入时,IDEA会出现弱警告,如下:
思考:为什么不推荐使用,这种方式是不是有更好的替代方案。
依赖注入方式
依赖注入有三种方式:
- 基于字段注入
- 基于构造器注入
- 基于set方法注入
1、基于字段注入
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeMapper employeeMapper;
}
优点:
- 注入方式简单:字段上附上注解@AutoWired即可。
- 可观性强:整体代码简洁明了。
缺点:
- 无法用于final修饰的变量
final类型的变量在调用class的构造函数的这个过程当中就得初始化完成,这个是基于字段的依赖注入做不到的地方,只能使用基于构造函数的依赖注入的方式. - 掩饰单一职责的设计思想
如果采用的是基于构造函数的依赖注入来使用Spring的IOC,当你注入的太多的时候,这个构造方法的参数就会很庞大,类似于下面。当你看到这个类的构造方法那么多参数的时候,你自然而然的会想一下:这个类是不是违反了单一职责思想?
但是使用基于字段的依赖注入不会让你察觉,你会很沉浸在@Autowire当中。public class VerifyServiceImpl implents VerifyService{ private AccountService accountService; private UserService userService; private IDService idService; private RoleService roleService; private PermissionService permissionService; private EnterpriseService enterpriseService; private EmployeeService employService; private TaskService taskService; private RedisService redisService; private MQService mqService; public SystemLogDto(AccountService accountService, UserService userService, IDService idService, RoleService roleService, PermissionService permissionService, EnterpriseService enterpriseService, EmployeeService employService, TaskService taskService, RedisService redisService, MQService mqService) { this.accountService = accountService; this.userService = userService; this.idService = idService; this.roleService = roleService; this.permissionService = permissionService; this.enterpriseService = enterpriseService; this.employService = employService; this.taskService = taskService; this.redisService = redisService; this.mqService = mqService; } }
- 与Spring的IOC机制紧密耦合
使用基于字段的依赖注入方式的时候,把控制权全给Spring的IOC了,别的类想重新设置下你的某个注入属性,没法处理(当然反射可以做到)。
本身Spring的目的就是解藕和依赖反转,结果通过再次与类注入器(在本例中为Spring)耦合,失去了通过自动装配类字段而实现的对类的解耦,从而使类在Spring容器之外无效.。
即对于IOC容器以外的环境,除了使用反射来提供它需要的依赖之外,无法复用该实现类。 - 隐藏依赖性
当使用Spring的IOC的时,被注入的类应当使用public类型的方法(构造方法,setter类型方法)来向外界表达:我需要什么依赖。
但是基于字段的依赖注入的方式,基本都是private形式的,private把属性都给封印到class当中了。 - 无法对注入的属性进行安全检查
在程序启动的时候无法拿到这个类,只有在真正的业务使用的时候才会拿到,若注入的是null,因为不调用将一直无法发现NullPointException的存在。
或者想在属性注入的时候,增加验证措施,也无法办到。
2、构造器注入
@Controller
@RequestMapping("employee")
public class EmployeeController {
private final EmployeeMapper employeeMapper;
@Autowired
public EmployeeController(EmployeeMapper employeeMapper) {
this.employeeMapper = employeeMapper;
}
}
优点:
- 保证依赖不可变(final关键字)。
- 保证依赖不为空(省去了我们对其检查)。
- 保证返回客户端(调用)的代码的时候是完全初始化的状态。
- 避免了循环依赖。
- 提升了代码的可复用性。
- 可以明确成员变量的注入顺序。
缺点:
当注入参数较多时,代码臃肿。
3、set方法注入
@Controller
@RequestMapping("employee")
public class EmployeeController {
private EmployeeMapper employeeMapper;
@Autowired
public void setEmployeeMapper(EmployeeMapper employeeMapper) {
this.employeeMapper = employeeMapper;
}
}
优点:
- 相比构造器注入,set注入类似于选择性注入。
- 允许在类构造完成后重新注入。
缺点:
暂无
总结
- 通过上面,我们可以看到,基于字段的依赖注入方式有很多缺点,我们应当避免使用基于字段的依赖注入。
- 对于必需的依赖项,建议使用基于构造函数的注入,以使它们成为不可变的,并防止它们为null。
- 对于可选的依赖项,建议使用基于Setter的注入。
参考资源
spring系列之-使用@Autowired注解,出现提示信息Field injection is not recommended
@Autowire和@Resource注解使用的正确姿势,这些年我一直用错了!!
更多推荐
已为社区贡献1条内容
所有评论(0)