Spring注入使用规范
首先本文将列出Spring中常见的依赖注入形式,并说明哪些注入形式推荐使用,哪些注入形式不推荐使用。并且会列出各种注入形式之间的差异。
私有字段上使用@Autowired注入(不推荐)
是否推荐:不推荐
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
}
这种注入形式违背了 SnoarLint
中的 java:S6813
规则:Field dependency injection should be avoided
代码检查中会提示:Remove this field injection and use constructor injection instead.(移除字段的形式的注入,使用构造函数注入代替)。
Field dependency injection should be avoided的详细描述
除了违背了 SnoarLint
中的 java:S6813
规则外,这种注入方式还有一个问题,就是它破坏了破坏类的封装性。使得私有字段被强行访问。
使用构造函数注入
是否推荐:推荐
@Service
public class UserServiceImpl implements UserService {
@Autowired
private final UserMapper userMapper;
public UserServiceImpl(UserMapper userMapper) {
this.userMapper = userMapper;
}
}
定义的字段上必须加上 final
关键字来修饰。推荐使用这种方式注入,这也是当前Spring推荐使用的注入方式。
这种注入形式会带来循环依赖无法解决的问题。但是如果出现循环依赖的问题,首先要考虑自己的程序设计是否合理。
在Setter上使用@Autowired来注入
是否推荐:推荐
@Service
public class UserServiceImpl implements UserService {
private UserMapper userMapper;
@Autowired
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
}
这种方式不仅可以解决循环依赖问题,而且不会出现在私有字段上使用@Autowired
注入的问题。
但是会增加一定的代码量。如果注入的Bean比较多,Setter方法会使整个类看起来很乱。
使用lombok优化Setter注入
@Service
public class UserServiceImpl implements UserService {
@Setter(onMethod_={@Autowired})
private UserMapper userMapper;
}
以上是JDK8+的使用方法,JDK7的使用方法如下:
@Service
public class UserServiceImpl implements UserService {
@Setter(onMethod=@__({@Autowired}))
private UserMapper userMapper;
}
使用@Inject注入(不推荐)
是否推荐:不推荐
@Inject 是 JSR330 (Dependency Injection for Java) 规范中的一个注解。与@Autowired的功能基本一致。通常与@Named一起使用
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
@Service
public class UserServiceImpl implements UserService {
private UserMapper userMapper;
@Inject
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
}
当需要指定要注入Bean的具体名称时,需要和@Named
一起使用。
@Service
public class UserServiceImpl implements UserService {
private UserMapper userMapper;
@Named("userMapper")
@Inject
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
}
但是这个注解不常使用,容易使其他开发者产生疑惑,故不推荐使用。
抽象类(或父类)构造函数注入问题
如果抽象类的构造函数注入的Bean比较多,那这种注入方式就会带来一些弊端。由于子类需要覆盖父类的构造函数,这也会导致子类构造函数中需要注入的Bean比较多。而且父类构造函数修改,会影响到所有子类。
为解决这个问题,我们可以让父类通过Setter
来注入,这样子类在继承父类之后不需要再通过父类的构造函数注入,而是相当于也有了一个Setter
注入方法。且父类的修改不会影响到子类。
@Service
public abstract class AbstractUserService {
@Setter(onMethod_={@Autowired})
private UserMapper userMapper;
}
@Service
public class UserServiceImpl extends AbstractUserService implements UserService {
@Setter(onMethod_={@Autowired})
private OtherMapper otherMapper;
}