前言

在进行属性注入时,@Autowired@Resource这两个注解经常在项目中可以看到,所以探讨下这两个注解有什么区别

相同点

接口有单一实现类时,针对接口的注入,两者可以互相替换,功能是一样的。

不同点

1、@AutowiredSpring中的注解。@ResourceJava中的注解

2、@Resource可以指定byNamebyType策略注入,默认是byName,如果根据name找不到,就会根据type注入。

@Autowired只能根据type注入,如果有多个type类型,可以配合@Qualifier注解来根据名称注入

代码展示-@Autowired

@Autowired源码定义:

auto

首先定义一个需要被注入的接口类型

1
2
3
4
5
6
7
@Repository
public interface UserRepository {
User getUserById(Long id);
void saveUser(User user);
List<User> getAllUsers();
// ...
}

下面就演示注入UserRepository的过程

1. @Autowired在构造函数上的使用

在构造函数上加上@Autowired注解,Spring就能够自动装配依赖。下面是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
@Service
public class UserServiceImpl implements UserService {

private final UserRepository userRepository;

@Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}

// ...
}

在上面的代码中,使用@Autowired注解来自动装配UserRepository类型的依赖。由于没有使用任何的限定符(Qualifier)Spring会根据type来匹配依赖关系。需要注意的是,使用构造函数注入时,不需要显式地声明依赖关系的成员变量。

2. @Autowired在方法上的使用

可以在方法上声明需要自动装配的依赖。下面是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
@Service
public class UserServiceImpl implements UserService {

private UserRepository userRepository;

@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}

// ...
}

在上面的代码中,使用@Autowired注解来自动装配UserRepository类型的依赖。需要注意的是,方法名并不是固定的,可以根据自己的需要进行命名。

3. @Autowired在参数上的使用

还可以在方法参数上使用它。下面是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
javaCopy code
@Service
public class UserServiceImpl implements UserService {

private final UserRepository userRepository;

@Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}

public void setUserService(@Autowired UserService userService) {
// ...
}

// ...
}

4. @Autowired在字段上的使用

在字段上使用时最常用的用法。下面是一个示例:

1
2
3
4
5
6
7
8
@Service
public class UserServiceImpl implements UserService {

@Autowired
private UserRepository userRepository;

// ...
}

5. @Autowired在注解类型上的使用

除了在构造函数、方法、参数和字段上使用@Autowired注解,还可以在注解类型上使用它。这样,Spring会自动装配标记了这个注解的类。下面是一个示例:

1
2
3
4
5
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Autowired
public @interface CurrentUser {
}

在上面的代码中,定义了一个注解类型@CurrentUser,并使用@Autowired注解标记它。这意味着,当在其他类中使用了@CurrentUser注解时,Spring会自动装配这个依赖。下面是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Service
public class UserServiceImpl implements UserService {

private final UserRepository userRepository;

@Autowired
public UserServiceImpl(UserRepository userRepository, @CurrentUser User currentUser) {
this.userRepository = userRepository;
// ...
}

// ...
}

问题

有多个类型的bean怎么办?

1
2
3
4
5
6
7
8
9
10
11
@Repository
public class UserRepositoryImpl implements UserRepository {

// ...
}

@Repository
public class UserRepositoryImpl2 implements UserRepository {

// ...
}

如果还按照上面根据类型注入,就会出现异常

1
2
3
4
5
6
7
8
@Service
public class UserServiceImpl implements UserService {

@Autowired
private UserRepository userRepository; // 因为有2个类型,这里出现异常

// ...
}

解决方案

1、使用@Autowired

1.1 使用@Qualifier注解

可以使用@Qualifier注解指定需要注入的Bean的名称。需要注意的是,这里的名称是Bean的名称,而不是属性名或类名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Repository("userRepositoryImpl")   // 指定Bean的名称
public class UserRepositoryImpl implements UserRepository {

// ...
}

@Repository("userRepositoryImpl2")
public class UserRepositoryImpl2 implements UserRepository {

// ...
}


@Service
public class UserServiceImpl implements UserService {

@Autowired
@Qualifier("userRepositoryImpl")
private UserRepository userRepository; // 会自动装配名称为"userRpositoryImpl"的Bean

// ...
}

1.2 使用@Primary注解

还可以使用@Primary注解标记一个Bean为首选Bean。这样在自动装配时,Spring会优先选择带有@Primary注解的Bean进行装配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Repository
@Primary // 指定首选Bean
public class UserRepositoryImpl implements UserRepository {

// ...
}

@Repository
public class UserRepositoryImpl2 implements UserRepository {

// ...
}

@Service
public class UserServiceImpl implements UserService {

@Autowired
private UserRepository userRepository; // 会自动装配类型为UserRepository,且选择了带有@Primary注解的Bean

// ...
}

2、使用@Resource

2.1 按类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Repository
public class UserRepositoryImpl implements UserRepository {

// ...
}

@Repository
public class UserRepositoryImpl2 implements UserRepository {

// ...
}


@Service
public class UserServiceImpl implements UserService {

@Resource(type = UserRepositoryImpl2.class)
private UserRepository userRepository; // 会自动装配类型为UserRepositoryImpl2的Bean

// ...
}

2.2 按名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Repository("userRepositoryImpl")   // 指定Bean的名称
public class UserRepositoryImpl implements UserRepository {

// ...
}

@Repository("userRepositoryImpl2")
public class UserRepositoryImpl2 implements UserRepository {

// ...
}


@Service
public class UserServiceImpl implements UserService {

@Resource(name = "userRepositoryImpl2")
private UserRepository userRepository; // 会自动装配名称为"userRepositoryImpl2"的Bean

// ...
}