spring可以通过@Resource
注解注入依赖,和@Autowired
存在区别:
@Autowired
默认按类型注入,而@Resource
默认按名称和类型结合注入@Autowired
支持通过属性required
设置为非必须注入,当依赖不存在时不会报错;@Resource
注解不支持@Autowired
能够配合@Qualifier
、@Primary
、@Priority
共同使用
那么spring实现@Resource
注解注入依赖的原理是什么,现在可以看下,逻辑不复杂,先判断容器中是否包含需要注入的依赖bean实例对象,没有的话就跟@Autowired
解析注入的依赖的方式一样,可以看我前一篇**@Autowired依赖注入原理**,存在的话则到容器中根据name和type获取依赖bean实例对象。
java
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
......
if (factory instanceof AutowireCapableBeanFactory) {
AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
DependencyDescriptor descriptor = element.getDependencyDescriptor();
//容器中没有依赖bean实例对象,则走@Autowired自动注入逻辑
if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet<>();
resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
if (resource == null) {
throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
}
}
//到容器中获取根据name和type获取bean实例对象
else {
resource = beanFactory.resolveBeanByName(name, descriptor);
autowiredBeanNames = Collections.singleton(name);
}
}
else {
resource = factory.getBean(name, element.lookupType);
autowiredBeanNames = Collections.singleton(name);
}
......
return resource;
}
//调用BeanFactory的getBean方法根据name和type获取bean实例对象
public Object resolveBeanByName(String name, DependencyDescriptor descriptor) {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
return getBean(name, descriptor.getDependencyType());
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
获取到依赖bean实例对象后,就会以反射方式set到字段中,进而完成依赖注入。这里可以看出@Resource
获取依赖再注入到字段的逻辑相对简单,虽然使用起来没有@Autowired
灵活,但是效率会高很多。
java
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
//反射注入依赖到字段
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
总结下,spring处理通过@Resource
注解注入依赖时,会到容器中根据name和type获取依赖bean实例对象,再反射set注入,更多请关注微信公众号 葡萄开源