1.背景
@Resource
和@Autowired
都是实现bean的注入,在日常开发中使用非常频繁,但是使用体验不太一样,笔者喜欢用@Resource
,因为在使用@Autowired
时IDEA会出现一些警告爆红提示:
Field injection is not recommended (字段注入是不被推荐的)
Spring团队不推荐属性字段注入的方式(ps:日常开发中我们一般都是字段注入,简单了然呀),建议使用基于构造函数的依赖项注入。
还有报红如下:IDEA提示找不到该类型的bean,这并不是错误。。。项目启动时mapper bean会被注入到Spring上下文容器中
综上情况和个人有强迫症看到警告和爆红就认为代码写得有问题,所以我选择了@Resource
。但是这里要申明一下@Autowied
本身是没问题的,可以尽情使用,出现以上报红是IDEA工具的问题。
项目推荐:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装,解决业务开发时常见的非功能性需求,防止重复造轮子,方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化,做到可插拔。严格控制包依赖和统一版本管理,做到最少化依赖。注重代码规范和注释,非常适合个人学习和企业使用
Github地址:https://github.com/plasticene/plasticene-boot-starter-parent
Gitee地址:https://gitee.com/plasticene3/plasticene-boot-starter-parent
微信公众号:Shepherd进阶笔记
2.概述
Spring 支持使用@Autowired
, @Resource
注解进行依赖注入
2.1 @Autowired和@Resource定义
@Autowired
@Autowired
为Spring 框架提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired
。源码如下
/**
* @since 2.5
* @see AutowiredAnnotationBeanPostProcessor
* @see Qualifier
* @see Value
*/
@Target({
ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
① 按照type
在上下文中查找匹配的bean,查找type为Svc的bean
② 如果有多个bean,则按照name
进行匹配
- 如果有
@Qualifier
注解,则按照@Qualifier
指定的name
进行匹配,查找name为svcA的bean
- 如果没有,则按照变量名进行匹配,
查找name为svcA的bean
③ 匹配不到,则报错。(@Autowired(required=false)
,如果设置required
为false
(默认为true
),则注入失败时不会抛出异常
@Resource
@Resource
是JDK1.6支持的注解,由J2EE提供,需要导入包javax.annotation.Resource
。源码如下:
@Target({
TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
String name() default "";
String lookup() default "";
Class<?> type() default java.lang.Object.class;
enum AuthenticationType {
CONTAINER,
APPLICATION
}
AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
boolean shareable() default true;
String mappedName() default "";
String description() default "";
}
默认按照名称进行装配,名称可以通过name属性进行指定。也提供按照byType 注入。
@Resource
有两个重要的属性:name 和 type,而Spring将@Resource
注解的name属性解析为bean的名字,而type属性则解析为bean的类型
如果没有指定name属性,当注解写在字段上时,默认取字段名,按照名称查找。
当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。
当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
@Resource
的作用相当于@Autowired
,只不过@Autowired
按照byType自动注入
2.2 @Autowired和@Resource区别
依赖识别方式:@Autowired默认是byType可以使用@Qualifier指定Name,@Resource默认ByName如果找不到则ByType
适用对象:@Autowired可以对构造器、方法、参数、字段使用,@Resource只能对方法、字段使用
提供方:@Autowired是Spring提供的,@Resource是JSR-250提供的
3.实现原理
3.1 @Autowired实现原理
Spring中通过AutowiredAnnotationBeanPostProcessor
来解析注入注解为目标注入值。该class继承InstantiationAwareBeanPostProcessorAdapter
,实现了MergedBeanDefinitionPostProcessor
,PriorityOrdered
, BeanFactoryAware
等接口,重写的方法将在IOC创建bean的时候被调用。
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware{
/**
* Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's
* standard {@link Autowired @Autowired} and {@link Value @Value} annotations.
* <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
* if available.
*/
@SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
......
}
前面已经提到了是Spring创建bean的时候调用,即当使用DefaultListableBeanFactory
来获取想要的bean的时候会调用AutowiredAnnotationBeanPostProcessor
,经过调用AbstractBeanFactory
中的getBean方法,继续追踪源码最后在AbstractAutowireCapableBeanFactory
类中的createBean
方法中找到了调用解析@autowired的方法:doCreateBean()
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
......
// Allow post-processors to modify the merged bean definition.
// 判断是否有后置处理
// 如果有后置处理,则允许后置处理修改 BeanDefinition
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 重点 重点 重点
// 这里会调用AutowiredAnnotationBeanPostProcessor查找解析注入的元信息
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
......
// Initialize the bean instance.
// 开始初始化 bean 实例对象
Object exposedObject = bean;
try {
// 对 bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 bean 的属性
// 则会递归初始依赖 bean
populateBean(beanName, mbd, instanceWrapper);
// 调用初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
.......
return exposedObject;
}
执行到applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName)
时会调用AutowiredAnnotationBeanPostProcessor
的postProcessMergedBeanDefinition()
完成注入元信息的查找解析。
进入populateBean()
方法:会调用AutowiredAnnotationBeanPostProcessor
方法postProcessPropertyValues()
方法完成属性值注入,因为AutowiredAnnotationBeanPostProcessor
是继承了InstantiationAwareBeanPostProcessorAdapter
,是一个后置处理器。
接下来基于这两个核心入口分别讲述一下:
查找解析元信息
实现了接口类MergedBeanDefinitionPostProcessor
的方法postProcessMergedBeanDefinition
,这个方法是合并我们定义类的信息,比如:一个类继承了其它类,这个方法会把父类属性和信息合并到子类中
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 根据bean的名称、类型查找注入的元信息
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
findAutowiringMetadata()
代码如下:
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
//先读缓存
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
//把查找出来的元信息进行构建
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
构建注解元信息 buildAutowiringMetadata()
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
//判断是否符合条件注解类型(@AutoWired和@Value)
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
//先处理注解字段
ReflectionUtils.doWithLocalFields(targetClass, field -> {
//是不是要找的字段
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
//静态字段不支持@Autowired
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
//再处理注解方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
//@Autowired不支持静态方法
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
基于上面方法找到了所有需要注入的元信息并进行解析,这个过程也是一个依赖查找过程。
属性值注入
属性注入的通过AutowiredAnnotationBeanPostProcessor
方法postProcessPropertyValues()
方法完成的
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//元信息查找、解析,在上一步已经分析过了
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//进行注入
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
//注入
element.inject(target, beanName, pvs);
}
}
}
/**
* Either this or {@link #getResourceToInject} needs to be overridden.
*/
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();
}
}
}
自此基于@Autowired
依赖注入核心逻辑就实现了。
3.2 @Resource实现原理
@Resource
和@Autowired
的实现逻辑和流程基本是一样的,只是@Resource
是通过CommonAnnotationBeanPostProcessor
实现的,这里由于具体逻辑和实现细节和上面的@Autowired
差不多,这里就不再赘述。