共计 5071 个字符,预计需要花费 13 分钟才能阅读完成。
咱们常常注入的形式都是相似这样子的
@Service | |
public class HelloService { | |
@Autowired | |
private BeanFactory beanFactory; | |
@Autowired | |
public HelloService(ApplicationContext applicationContext) { } | |
@Autowired | |
public void setEnvironment(Environment environment) {}} |
不论是构造函数注入还是属性注入、咱们都能够称为显式注入。
咱们再来看看一个咱们罕用的注解 @Bean
public @interface Bean {@AliasFor("name") | |
String[] value() default {}; | |
@AliasFor("value") | |
String[] name() default {}; | |
@Deprecated | |
Autowire autowire() default Autowire.NO; | |
boolean autowireCandidate() default true; | |
String initMethod() default ""; | |
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;} |
咱们关注的属性 autowire
尽管标注曾经被废除了、然而不障碍咱们理解一下它。
NO
默认值、代表不会主动注入BY_NAME
、通过beanName
进行主动注入BY_TYPE
、通过参数的类型进行主动注入
Autowire.NO
@Configuration | |
public class Config {@Bean(autowire = Autowire.NO) | |
public HelloService helloService() {return new HelloService(); | |
} | |
} | |
public class HelloService {public void setEnvironment(Environment environment) {System.out.println("invoke" + environment); | |
} | |
} |
咱们应用默认的配置、不对 HelloService
进行主动注入、毫无疑问、setEnvironment
是不会被 Spring 框架调起的。
Autowire.BY_NAME
咱们将下面的代码改为
@Bean(autowire = Autowire.BY_NAME)
会发现 setEnvironment
被调起、并且参数 environment 就是 Spring 中的 StandardServletEnvironment
这一步如果对 Spring 获取 bean 流程有印象的、Spring 获取单例流程 (三) 能够得悉其在 AbstractAutowireCapableBeanFactory#populateBean 中被调用
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {MutablePropertyValues newPvs = new MutablePropertyValues(pvs); | |
// 将主动注入的值放入到 newPvs 中 | |
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs); | |
} | |
// Add property values based on autowire by type if applicable. | |
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs); | |
} | |
pvs = newPvs; | |
} | |
.......... | |
if (pvs != null) {applyPropertyValues(beanName, mbd, bw, pvs); | |
} |
对应的代码也是十分的简略的
protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { | |
// 依据 setter 办法获取须要次要的 beanName、解释 setter 办法 | |
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); | |
for (String propertyName : propertyNames) { | |
// 如果不在 BeanFactory 中、间接疏忽、不会报错 | |
if (containsBean(propertyName)) {Object bean = getBean(propertyName); | |
// 退出到 pvs 中 | |
pvs.add(propertyName, bean); | |
registerDependentBean(propertyName, beanName); | |
} | |
else {// 如果不存在该 bean、不报错、间接疏忽} | |
} | |
} |
能够看到 BY_NAME 的形式、是通过解释 setter 办法名来获取须要注入的 beanName。如果 beanName 不存在 BeanFactory 中、间接疏忽、相似于 @Autowired(required=false)。不是强制性注入
然而你的办法名称必须是 setXxx 结尾、合乎肯定的命名规定、跟 BeanInfo 的规定相似 (Java 内省)、然而比它宽松、这里不限定返回值肯定要是 void
Autowire.BY_TYPE
autowireByType
protected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { | |
....... | |
Set<String> autowiredBeanNames = new LinkedHashSet<>(4); | |
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); | |
// 遍历 setter 办法解释获取其属性名 | |
for (String propertyName : propertyNames) { | |
try {PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName); | |
if (Object.class != pd.getPropertyType()) {MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd); | |
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered); | |
// AutowireByTypeDependencyDescriptor 这个类很要害、它返回的 getDependencyName 始终为 null | |
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager); | |
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter); | |
if (autowiredArgument != null) {pvs.add(propertyName, autowiredArgument); | |
} | |
for (String autowiredBeanName : autowiredBeanNames) {registerDependentBean(autowiredBeanName, beanName); | |
} | |
autowiredBeanNames.clear();} | |
} | |
catch (BeansException ex) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex); | |
} | |
} | |
} |
跟 BY_NAME 很类似的、那如果我主动注入的对象不存在 BeanFactory 中、是不是也不会抛异样呢?答案是的、这里次要是因为应用了这个类 AutowireByTypeDependencyDescriptor
private static class AutowireByTypeDependencyDescriptor extends DependencyDescriptor {public AutowireByTypeDependencyDescriptor(MethodParameter methodParameter, boolean eager) {super(methodParameter, false, eager); | |
} | |
@Override | |
public String getDependencyName() {return null;} | |
} | |
// 父类 | |
public DependencyDescriptor(MethodParameter methodParameter, boolean required, boolean eager) {super(methodParameter); | |
....... | |
this.required = required; | |
....... | |
} |
第一个关键点就是 requied 为 false、当所依赖的 bean 不存在 BeanFactory 的时候、false 则不会抛异样。
第二个关键点则是、如果存在两个雷同的 bean、如果这两个 bean 都没有申明 Primary 或者 PriorityOrderd 的话、那么它还是会抛出异样的、而不会依据 beanName 去匹配筛选出适合的 bean、因为 getDependencyName 始终返回 null
这种状况跟 @Autowired 的形式不太一样、因为 BY_TYPE 的形式是不依赖 beanName 的
@Nullable | |
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {Class<?> requiredType = descriptor.getDependencyType(); | |
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType); | |
if (primaryCandidate != null) {return primaryCandidate;} | |
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType); | |
if (priorityCandidate != null) {return priorityCandidate;} | |
// Fallback | |
for (Map.Entry<String, Object> entry : candidates.entrySet()) {String candidateName = entry.getKey(); | |
Object beanInstance = entry.getValue(); | |
// resolvableDependencies | |
if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) || | |
// BY_TYPE matchesBeanName 返回 false | |
matchesBeanName(candidateName, descriptor.getDependencyName())) {return candidateName;} | |
} | |
return null; | |
} |
resolvableDependencies 中寄存 key-value 的状况
总结
主动注入绝对显式注入、在理论场景中的确用得比拟少、然而理解其过程还是会让你播种到一些相干的常识和流程
给本人和所有看到这篇文章的同学加油~!!
微信公众号:CoderLi