@Inject与@AutoWired一致,区别在于@Inject没有required属性
4、
@Inject:通过AutowiredAnnotationBeanPostProcessor类实现依赖注入
@Autowired:通过AutowireAnnotationBeanPostProcessor类实现依赖注入
@Resource:通过CommonAnnotationBeanPostProcessor类实现依赖注入。
5、Spring的IOC注入过程
在Spring所管理的类里面,在要注入的对象属性或者setter方法加上上面三个任意一个注解或者在xml文件中配置
上述步骤可以分解为以下几个步骤,如图所示:
每次调用getBean时并不总是会调用doCreateBean方法,如果要获取的对象是singleton的,会先从工厂里面获取,否则会走这个流程。但无论是singleton还是prototype还是scope为其他类型,都会走一遍这个流程。
具体来看populateBean()方法:
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues(); //当前bean要注入的属性
if (bw == null) {
if (!pvs.isEmpty()) { //要注入的属性不为空,但beanWrapper为空 抛出异常
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
return;
}
}
boolean continueWithPropertyPopulation = true;
//这儿处理注解配置,使用不同的注解注入的类会有所不同
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;break;
}
}
}
}
if (!continueWithPropertyPopulation) { //是否需要注入属性,不需要则bean构造已完成
return;
}
//处理注入类型,byName还是byType, 注解的注入不会进入这儿,配置文件不指定autowire或者指定为default也不会进入这儿
//这儿并没有完成IOC,只是根据名字或者类型找到对应bean
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
//注解注入,xml的配置不会走这儿
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
//其他注入,如List Map等,xml配置的注入也是在这个方法完成的
applyPropertyValues(beanName, mbd, bw, pvs);
}
不管是xml的配置还是注解配置,要注入前都会有一个寻找目标bean的过程。这个过程在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory的resolveDependency方法中,具体实现在DefaultListableBeanFactory中,最终会调用DefaultListableBeanFactory的doResolveDependency方法。
下面是该方法的部分源代码:
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
Set autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
//如果要注入的List、Map类型
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
//如果要注入的是单个对象,不是集合类型
//根据类型来查找匹配的bean
Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) { //没找到匹配的bean,会根据是否设置了required=true来抛出异常
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
//找到的bean的个数大于1
if (matchingBeans.size() > 1) {
//通过名字来匹配
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) { //没找到名字匹配的bean,根据是否设置了required抛出异常
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(type, matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
//这种情况下根据类型找到了唯一的bean
// We have exactly one match.
Map.Entry entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
return (instanceCandidate instanceof Class ?
descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
}
xml的配置方式注入寻找bean过程在autowireByType方法中调用了,而注解的方式注入是根据直接注入属性还是通过方法注入划分为了两个类,如图:
然后在各自的inject方法中调用resolveDependency方法。最后根据java reflect反射设置进去,这也是为什么在private属性上加上注解依旧能注入进去的原因。
而xml最终是使用下面的图上的类来完成注入的:
注入完成后代表构造bean的过程结束,最终会将构造完成的bean返回给调用者。
整个过程如图:
需要注意的是:
1、注解注入比xml配置注入先发生。
2、找寻bean的过程,根据类型匹配到的bean的个数如果大于1,并不是马上根据name匹配,而是先寻找有@Primary注解的bean,如果没有则寻找@Order注解的bean并且@Order的value属性最小的bean,如果@Primary和@Order都没找到,则会根据field的name匹配。ps:好像@Order配置bean不起作用
3、如果使用@Autowired注入并且使用@Qualifier指定name,则查找时会根据类型与名字查找,如果查找结果为空,则会抛出异常。
4、如果使用@Resource指定name属性与第三点一致。
所以当不指定bean的name属性时:
当指定name时:
最后注入时注解最好加在setter方法上面,因为field属性一般都是声明为private,通过反射不能直接访问,会调用setAccessible(true),但这个方法可能会因为权限不足而抛出异常。
以上就是个人理解的Spring IOC注入过程。但因个人水平原因,可能不全面或者有不对的地方,欢迎评论留言。