#yyds干货盘点# @Autowired注解到底怎么实现的?

Posted 公众号JavaEdge

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#yyds干货盘点# @Autowired注解到底怎么实现的?相关的知识,希望对你有一定的参考价值。


1 @Autowired 干嘛的?

用来执行依赖注入.每当一个Spring管理的bean发现有该注解时,会直接注入相应的另一个Spring管理的bean.

1.1 不同地放置有不同作用

  • 属性
    Spring将通过扫描自定义的package或通过在配置文件中直接查找bean
  • 方法
    使用@Autowired注解的每个方法都要用到依赖注入
    但要注意的是,签名中呈现的所有对象都必须是Spring所管理的bean
    如果你有一个方法,比如​​setTest(Article article, NoSpringArticle noSpringArt)​​ ,其中只有一个参数 (Article article)是由Spring管理的,那么就将抛出一个org.springframework.beans.factory.BeanCreationException异常
    这是由于Spring容器里并没有指定的一个或多个参数所指向的bean,所以也就无法解析它们

1.2 bean的注入方式

  • 名称
    bean解析是通过bean名称
  • 类型
    解析基于bean的类型

1.3 @Qualifier 协作

如下相同类型的bean

<bean name="article1" class="com.sss.Article">
<property name="text" value="Content of the 1st Article" />
</bean>
<bean name="article2" class="com.sss.Article">
<property name="text" value="Content of the 2nd Article" />
</bean>

假如只是一个简单的@Autowired,Spring根本不知道你要注入哪个bean。这就需要@Qualifier(value =“beanName”)协作.

譬如,要从 ​​com.javaedge.Article​​类型的bean中区分article1,article2:

@Qualifier(value="article1")
@Autowired
private Article firstArticle;
@Qualifier(value="article2")
@Autowired
private Article secondArticle;

2 优雅地使用@Autowired

启动自动注入

<context:annotation-config />

放在应用程序上下文配置。可以使在遇到@Autowired注解时启用依赖注入

  • bean

// beans first
public class Comment
private String content;
public void setContent(String content)
this.content = content;

public String getContent()
return this.content;


// sample controller
@Controller
public class TestController
@Qualifier(value="comment1")
@Autowired
private Comment firstComment;
@Qualifier(value="comment2")
@Autowired
private Comment secondComment;
@RequestMapping(value = "/test", method = RequestMethod.GET)
public String test()
System.out.println("1st comment text: "+firstComment.getText());
System.out.println("2nd comment text: "+secondComment.getText());
return "test";


// no-Spring managed class
public class TestNoSpring
@Autowired
private Comment comment;
public void testComment(String content)
if (comment == null)
System.out.println("Comments instance wasnt autowired because this class is not Spring-managed bean");
else
comment.setContent(content);
System.out.println("Comments content: "+comment.getContent());



  • 配置

<bean name="comment1" class="com.sss.exchanger.Comment">
<property name="content" value="Content of the 1st comment" />
</bean>
<bean name="comment2" class="com.sss.exchanger.Comment">
<property name="content" value="Content of the 2nd comment" />
</bean>

打开http://localhost:8080/test来运行TestController

TestController的注解字段正确地自动注入,而TestNoSpring的注解字段并没有注入进去

1st comment text: Content of the 1st comment
2nd comment text: Content of the 2nd comment
Comments instance wasnt autowired because this class is not Spring-managed bean

哪里不对 ?TestNoSpring类不由Spring所管理

这就是为什么Spring不能注入Comment实例的依赖

3 隐藏在@Autowired注解背后的秘密

Spring管理可用于整个应用程序的Java对象bean,我们不需要处理他们的生命周期(初始化,销毁)。该任务由此容器来完成。

该上下文具有入口点,在Web应用程序中,是​​dispatcherservlet​​。

容器(也就是该上下文)会在它那里被启动并且所有的bean都会被注入

看<context:annotation-config />的定义

<xsd:element name="annotation-config">
<xsd:annotation>
<xsd:documentation><![CDATA[
Activates various annotations to be detected in bean classes: Springs @Required and
@Autowired, as well as JSR 250s @PostConstruct, @PreDestroy and @Resource (if available),
JAX-WSs @WebServiceRef (if available), EJB 3s @EJB (if available), and JPAs
choose to activate the individual BeanPostProcessors for those annotations.
Note: This tag does not activate processing of Springs @Transactional or EJB 3s
tag for that purpose.
See javadoc for org.springframework.context.annotation.AnnotationConfigApplicationContext
for information on code-based alternatives to bootstrapping annotation-driven support.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>

类内部的注解,如@Autowired、@Value、@Required、@Resource以及Web Serivce相关的注解,是容器对Bean对象实例化和依赖注入时,通过容器中注册的Bean后置处理器处理这些注解的

所以配置了上面这个配置(​​<context:component-scan>假如有配置这个,那么就可以省略<context:annotation-config />​​)后,将隐式地向Spring容器注册AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor以及这4个专门用于处理注解的Bean后置处理器。

当 Spring 容器启动时,AutowiredAnnotationBeanPostProcessor 将扫描 Spring 容器中所有 Bean
当发现 Bean 中拥有@Autowired 注解时就找到和其匹配(默认按类型匹配)的 Bean

并注入到对应的地方中去。

4 源码分析

通过org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor可以实现依赖自动注入

通过这个类来处理@Autowired @Value Spring

它也可以管理JSR-303的@Inject

  • 在​​AutowiredAnnotationBeanPostProcessor​​构造函数中定义要处理的注解
    #yyds干货盘点#
    #yyds干货盘点#

之后,有几种方法对@Autowired处理

第一个,private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz)解析等待自动注入类的所有属性。它通过分析所有字段和方法并初始化org.springframework.beans.factory.annotation.InjectionMetadata类的实例来实现。

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) 
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
Class<?> targetClass = clazz;
do
final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();
//分析所有字段
ReflectionUtils.doWithLocalFields(targetClass, field ->
//findAutowiredAnnotation(field)此方法后面会解释
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null)
if (Modifier.isStatic(field.getModifiers()))
if (logger.isWarnEnabled())
logger.warn("Autowired annotation is not supported on static fields: " + field);

return;

boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));

);
//分析所有方法
#yyds干货盘点#jackson学习之七:常用Field注解

#yyds干货盘点#jackson学习之五:JsonInclude注解

#yyds干货盘点# springboot使用@SpringBootTest注解进行单元测试

#yyds干货盘点#jackson学习之六:常用类注解

SpringCache #yyds干货盘点#

#yyds干货盘点# MySQL的普通索引和唯一索引到底什么区别?