【每天学点Spring】@Autowired,@Inject,@
@Autowired,@Inject,@Resource提供的功能都比较类似,都能实现依赖注入。但也有些许不同。
文章内容:

@Autowired
@Autowired是Spring提供的注解:
- 它先是按type进行注入。
- 如果有多个实现类,可以用@Qualifier注解来避免歧义,
- 最后才是按name匹配。
首先是按type匹配,UserService只有一个实现类,所以注入成功!
public interface UserService {
String getName();
}
@Service
public class DoctorUserServiceImpl implements UserService {
public String getName() {
return "DoctorUserServiceImpl";
}
}
@SpringBootTest
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void test() {
System.out.println(userService.getName()); // 打印结果:DoctorUserServiceImpl
}
}
如果此时UserService又多了一个实现类TeacherUserServiceImpl,
@Service
public class TeacherUserServiceImpl implements UserService {
public String getName() {
return "TeacherUserServiceImpl";
}
}
那么运行以上测试,会报错:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.faj.UserServiceTest': Unsatisfied dependency expressed through field 'userService'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.faj.inject.UserService' available: expected single matching bean but found 2: doctorUserServiceImpl,teacherUserServiceImpl
这时候,就要和@Qualifier一起使用:
UserService依旧有两个实现类:DoctorUserServiceImpl和TeacherUserServiceImpl:
@Service(value = "doctorUserService") // 给bean加上name
public class DoctorUserServiceImpl implements UserService {
public String getName() {
return "DoctorUserServiceImpl";
}
}
// TeacherUserServiceImpl代码同上,省略
@SpringBootTest
public class UserServiceTest {
@Autowired
@Qualifier(value = "doctorUserService") // 使用该注解避免type带来的歧义
private UserService userService;
@Test
public void test() {
System.out.println(abc.getName()); // 打印结果:DoctorUserServiceImpl
}
}
最后,@Autowired按name匹配:
@Service(value = "abc")
public class DoctorUserServiceImpl implements UserService {
public String getName() {
return "DoctorUserServiceImpl";
}
}
@Service // bean默认是类名(首字母小写)
public class TeacherUserServiceImpl implements UserService {
public String getName() {
return "TeacherUserServiceImpl";
}
}
@SpringBootTest
public class UserServiceTest {
@Autowired
private UserService abc; // 此时是按name匹配
@Autowired
private UserService teacherUserServiceImpl; // 此时是按name匹配
@Test
public void test() {
System.out.println(abc.getName()); // 打印结果:DoctorUserServiceImpl
System.out.println(teacherUserServiceImpl.getName()); // 打印结果:TeacherUserServiceImpl
}
}
@Inject
@Inject属于JSR-330定义的Java的依赖注入标准(https://www.jcp.org/en/jsr/detail?id=330),使用@Inject的时候需要先加上依赖:
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
@Inject的用法和@Autowired基本相似:
- 先按type注入
- 如果遇到多个实现类的情况,通过@Named进行区分。
- 最后按name匹配
Spring通过AutowiredAnnotationBeanPostProcessor处理注解@Autowired和@Inject。
不同点在于:@Autowired有个参数是required(默认为true),即在没有找到bean的时候,报NoSuchBeanDefinitionException;但如果required=false的时候,则不报错,会set null。举个例子:
@SpringBootTest
public class UserServiceTest {
@Autowired(required = false)
@Qualifier(value = "abc") // 并不存在name = abc的bean
private UserService userService;
@Test
public void test() {
System.out.println(userService); //此时的userService=null
}
}
@Inject则没有这个功能,如果找不到适配的bean,则会报错:
@SpringBootTest
public class UserServiceTest {
@Inject
@Named(value = "abc")
private UserService userService;
@Test
public void test() {
System.out.println(userService); // 报错
}
}
此时报错:org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.faj.inject.UserService' available: expected at least 1 bean which qualifies as autowire candidate.
@Resource
@Resource是JSR-250的规范,在实现依赖注入的时候,先按name进行匹配,其次是type,最后是@Qualifier。
Spring通过CommonAnnotationBeanPostProcesser来处理该注解。和@Inject不同的是,@Resource不需要额外引入jar包。