自动装配
spring会在上下文中自动查找Bean并注入到IOC容器中。
spring提供了四种自动装配策略
public interface AutowireCapableBeanFactory{
//无需自动装配
int AUTOWIRE_NO = 0;
//按名称自动装配bean属性
int AUTOWIRE_BY_NAME = 1;
//按类型自动装配bean属性
int AUTOWIRE_BY_TYPE = 2;
//按构造器自动装配
int AUTOWIRE_CONSTRUCTOR = 3;
//过时方法,Spring3.0之后不再支持
@Deprecated
int AUTOWIRE_AUTODETECT = 4;
}
1.ByName(按名称自动装配):
把与 bean
的属性具有相同名字的其他 bean
自动装配到 bean
的对应属性中
定义一个实体类并定义属性:
public class User{ private Role myRole; } public class Role { private String id; private String name; }
那么在configContext配置文件中的应该这样注入:
//用我们自定义的属性名注入IOC容器,class为类的完全限定名。
<bean id="myRole" class="com.viewscenes.netsupervisor.entity.Role"> <property name="id" value="1001"></property> <property name="name" value="管理员"></property> </bean> <bean id="user" class="com.viewscenes.netsupervisor.entity.User" autowire="byName"></bean>
2.ByType
把与 bean
的属性具有相同类型的其他 bean
自动装配到 bean
的对应属性中。
<bean id="myRole" class="com.viewscenes.netsupervisor.entity.Role"> <property name="id" value="1001"></property> <property name="name" value="管理员"></property> </bean> <bean id="user" class="com.viewscenes.netsupervisor.entity.User" autowire="byName"></bean>
3.Constructor
把与Bean的构造器入参具有相同类型的其他Bean自动装配到Bean构造器的对应入参中。值的注意的是,具有相同类型的其他Bean这句话说明它在查找入参的时候,还是通过Bean的类型来确定。
public class User{ private Role role; public User(Role role) { this.role = role; } } <bean id="user" class="com.viewscenes.netsupervisor.entity.User" autowire="constructor"></bean>
4、autodetect
它首先会尝试使用constructor进行自动装配,如果失败再尝试使用byType。不过,它在Spring3.0之后已经被标记为@Deprecated
。
@Autowired注解
从spring2.5开始,支持使用注解来自动装配bean属性,他允许更细粒度的属性装配,我们可以选择某一个属性来添加Autowired注解。
使用@Autowirded注解:
//在需要注入的属性前添加注解即可
@Autowired
UserService userService;
@Autowirded的几种特性:
1.强制性
默认情况下,它具有强制契约的特性,就是所标注的属性必须是可装配的,如果没有bean可以装配的属性,就会报错:NoSuchBeanDefinitionException。
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
// 查找Bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
// 如果拿到的 Bean 集合为空,且 isRequired 为 true,就抛出异常
if (matchingBeans.isEmpty()) {
if (descriptor.isRequired()) {
raiseNoSuchBeanDefinitionException(type, "", descriptor);
}
return null;
}
}
2.装配策略
(1)默认按照类型装配(findAutowireCandidates方法)
protected Map<String, Object> findAutowireCandidates(
String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 获取给定类型的所有 bean 名称,里面实际循环所有的 beanName,获取它的实例
// 再通过 isTypeMatch 方法来确定
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
// 根据返回的 beanName,获取其实例返回
for (String candidateName : candidateNames) {
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
result.put(candidateName, getBean(candidateName));
}
}
return result;
}
(2)按照类型没有找到时,按照名称装配
如果查到多个实例时,就会使用determineAutowireCandidate方法,即按照名称查询并装配。
protected String determineAutowireCandidate(Map<String, Object> candidateBeans,
DependencyDescriptor descriptor) {
// 循环拿到的 bean 集合
for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) {
String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue();
// 通过 matchesBeanName 方法来确定 bean 集合中的名称是否与属性的名称相同
if (matchesBeanName(candidateBeanName, descriptor.getDependencyName())) {
return candidateBeanName;
}
}
return null;
}
(3)主和优先级
如果既不能通过ByType装配,又不能通过ByName装配,就会使用determaneAutowiredCandidate 方法。
protected String determineAutowireCandidate(Map<String, Object> candidateBeans,
DependencyDescriptor descriptor) {
Class<?> requiredType = descriptor.getDependencyType();
// 通过 @Primary注解来标识 bean
String primaryCandidate = determinePrimaryCandidate(candidateBeans, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
// 通过 @Priority(value = 0) 注解来标识 bean, value 为优先级大小
String priorityCandidate = determineHighestPriorityCandidate(candidateBeans, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
return null;
}
通过俩种注解实现:
@primary
protected String determineAutowireCandidate(Map<String, Object> candidateBeans,
DependencyDescriptor descriptor) {
Class<?> requiredType = descriptor.getDependencyType();
//通过@Primary注解来标识Bean
String primaryCandidate = determinePrimaryCandidate(candidateBeans, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
//通过@Priority(value = 0)注解来标识Bean value为优先级大小
String priorityCandidate = determineHighestPriorityCandidate(candidateBeans, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
return null;
}
@Priority
protected String determinePrimaryCandidate(Map<String, Object> candidateBeans, Class<?> requiredType) {
String primaryBeanName = null;
for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) {
String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue();
if (isPrimary(candidateBeanName, beanInstance)) {
if (primaryBeanName != null) {
boolean candidateLocal = containsBeanDefinition(candidateBeanName);
boolean primaryLocal = containsBeanDefinition(primaryBeanName);
if (candidateLocal && primaryLocal) {
throw new NoUniqueBeanDefinitionException(requiredType, candidateBeans.size(),
"more than one 'primary' bean found among candidates: " + candidateBeans.keySet());
}
else if (candidateLocal) {
primaryBeanName = candidateBeanName;
}
}
else {
primaryBeanName = candidateBeanName;
}
}
}
return primaryBeanName;
}
Autowired实现原理总结:
- 在Spring3.0后,自动装配策略分为三种:ByType,By Name , constructor三种方式。
- 默认按照类型装配,如果存在多个实例,则按照ByName匹配,如果依旧确定不了,则按照prority或primany 注解来确定。