Spring MVC 解读——@Autowired、@Controller、@Service从原理层面来分析

本文深入探讨了Spring MVC中的@Autowired注解,揭示了其背后的自动装配机制。从BeanPostProcessor接口和AutowiredAnnotationBeanPostProcessor类的作用,到实例化和装配Bean的完整过程,详细解释了如何通过类型匹配进行自动装配。文章通过对源码的分析,梳理了Spring MVC在处理依赖注入时的步骤,展示了从bean工厂的getBean方法开始,到BeanPostProcessor的调用,以及@Autowired注解如何影响属性的赋值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring MVC 解读——@Autowired

一、@Autowired

    作为一个Spring开发者对@Autowired注解必定是非常了解了, 顾名思义自动装配,应该是Spring会自动将我们标记为@Autowired的元素装配好,与其猜测不如看看它的定义:

  1. @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD,  
  2.                          ElementType.ANNOTATION_TYPE})  
  3. @Retention(RetentionPolicy.RUNTIME)  
  4. @Documented  
  5. public @interface Autowired {  
  6.     boolean required() default true;  
  7. }  
 

 很明显这个注解可以用到构造器,变量域,方法,注解类型上。文档上这样描述:将一个构造器,变量域,setter方法,config方法标记为被Spring DI 工具自动装配。换句话说,我们视图从bean 工厂中获取一个bean时,Spring会自动为我们装配该bean中标记为@Autowired的元素,而无需我们手动完成。这些相信大家都明白,但问题是,Spring是怎样做到的?在Spring MVC中怎样做到的?什么时候进行的自动装配?下面我们就来探究下这些问题。

二、BeanPostProcessor

    在@Autowired的定义中有下面一段话:

  1. <pre name="code" class="java">Note that actual injection is performed through a BeanPostProcessor   
  2. which in turn means that you cannot use @Autowired to inject references into BeanPostProcessor  
  3. or BeanFactoryPostProcessor types.   
  4. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class   
  5. (which, by default, checks for the presence of this annotation).  
 

意思是:实际的注入装配动作是由BeanPostProcessor执行的,翻过来说你不能将@Autowired注解用于BeanPostProcessor或BeanFactoryPostProcessor类型上。请查看AutowiredAnnotationBeanPostProcessor文档(默认情况下,被用来检查@Autowired注解)。

    文档说的很清楚了,BeanPostProcessor来执行自动装配,并且默认情况下使用AutowiredAnnotationBeanPostProcessor实现类完成。那我们不妨看一下他们的定义:

?
 
  1. public interface BeanPostProcessor {  
  2.     Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;  
  3.     Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;  
  4. }  

   BeanPostProcessor就一个回调接口,定义了两个方法声明,一个是实例化前被调用,一个是实例化后被调用,没啥好看的,我们直接看看它的实现类AutowiredAnnotationBeanPostProcessor:


 

  1. BeanPostProcessor implementation that autowires annotated fields, setter methods and arbitrary   
  2. config methods. Such members to be injected are detected through a Java 5 annotation:   
  3. by default, Spring's @Autowired and @Value annotations.Also supports JSR-330'@Inject   
  4. annotation, if available, as a direct alternative to Spring's own @Autowired.  
  5.    
  6. Note: A default AutowiredAnnotationBeanPostProcessor will be registered by   
  7. the "context:annotation-config" and "context:component-scan" XML tags.  
  8.    
  9. NOTE: Annotation injection will be performed before XML   
  10. injection; thus the latter configuration will override the former for properties   
  11. wired through both approaches.  

   上面是AutowiredAnnotationBeanPostProcessor类的描述文档摘要,大致意思是:这是BeanPostProcessor接口的一个实现,用来自动装配注解的变量域,setter方法和任意的config方法。这些被注入的元素是通过检测Java 5的注解完成的:默认情况下是@Autowired和@Value注解。同样也支持JSR-330的@Inject注解。并且,<context:annotation-config/>和<context:component-scan/>XML标签可以默认注册AutowiredAnnotationBeanPostProcessor到bean工厂中。最后,注解注入会在XML注入之前执行;因此后面的配置会覆盖前面已经装配好的元素。

    是不是很清楚了?Spring的文档总是这么详细,要么说是教科书呢,废话不多说,我们才刚进正题呢,既然我们清楚了是AutowiredAnnotationBeanPostProcessor实例执行了自动装配,那么它做了什么呢?

三、磨刀砍柴   

在正式查看源码前,我先大致的讲一下整个装配的过程,以便后面理解起来轻松些。其实整体思路还是很简单的,我们举个简单的例子:


  1. //==================================Controller  
  2. @Controller  
  3. public class SimpleController {  
  4.     @Autowired  
  5.     private SimpleService simpleService;  
  6. }  
  7. //==================================Service  
  8. @Service("simpleService")  
  9. public class SimpleServiceImpl implements SimpleService {  
  10.     @Autowired  
  11.     private SimpleDao simpleDao;  
  12. }  
  13. //===================================Repository  
  14. @Repository("simpleDao")  
  15. public class SimpleDaoImpl implements SimpleDao {  
  16. }  

 

1)在某一时刻Spring调用了 Bean工厂 的 getBean(beanName) 方法。beanName可能是simpleController,或者simpleService,simpleDao,顺序没关系(因为后面会有依赖关系的处理)。我们假设simpleController吧。

2)getBean方法首先会调用Bean工厂中定义的getSingleton(beanName)方法,来判断是否存在该名字的bean单例,若果存在则返回,方法调用结束。

3)否则,Spring会检查是否存在父工厂,如果有则返回,方法调用结束。

4)否则,Spring 会检查该bean 定义(BeanDefinition实例,用来描述Bean结构,上篇文章讲到过,component-scan 扫描后,就是将beanDefinition实例放入Bean工厂,此时Bean还没有被实例化。)是否有依赖关系,如果有,执行1)步,获取依赖的bean实例。

5)否则,Spring会尝试创建这个bean实例,创建实例前,Spring会检查确定调用的构造器,并实例化该Bean。

6)实例化完成后,Spring会调用Bean工厂的populateBean方法来填充bean实例的属性,也就是我们前面提到的自动转配了。populateBean方法便是调用了BeanPostProcessor实例来完成属性元素的自动装配工作。

7)在元素装配过程中,Spring会检查被装配的属性是否存在自动装配的其他属性,然后递归调用getBean方法,直到所有@Autowired的元素都被装配完成。如在装配simpleController中的simpleService属性时,发现SimpleServiceImpl实例中存在@Autowired属性simpleDao,然后调用getBean(simpleDao)方法,同样会执行1)-7)整个过程。所以可以看成一个递归过程。

8)装配完成后,Bean工厂会将所有的bean实例都添加到工厂中来。

注:我们知道Spring MVC是多线程单实例的MVC框架,就是说,对于同一个Controller,只会生成一个实例来处理所有的请求,因此bean实例只会实例化一次,并被存放在工厂中,以供其他请求使用。

好了,大致了解整个流程后我们看一下Spring的具体行为吧。

四、Bean 工厂

    前面多次提到了Bean工厂,但一直没有说它到底是个什么,这里我们就彻底弄清楚吧,省的云里雾里,这样我们后面讲到Bean工厂就不会晕了。看过上一篇博客(<context:component-scan/>ÿ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值