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

Spring MVC 解读——@Autowired

一、@Autowired

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

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD,
                         ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}
 

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

二、BeanPostProcessor

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

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

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

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

?
 
public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

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


 

BeanPostProcessor implementation that autowires annotated fields, setter methods and arbitrary 
config methods. Such members to be injected are detected through a Java 5 annotation: 
by default, Spring's @Autowired and @Value annotations.Also supports JSR-330's @Inject 
annotation, if available, as a direct alternative to Spring's own @Autowired.
 
Note: A default AutowiredAnnotationBeanPostProcessor will be registered by 
the "context:annotation-config" and "context:component-scan" XML tags.
 
NOTE: Annotation injection will be performed before XML 
injection; thus the latter configuration will override the former for properties 
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实例执行了自动装配,那么它做了什么呢?

三、磨刀砍柴   

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


//==================================Controller
@Controller
public class SimpleController {
    @Autowired
    private SimpleService simpleService;
}
//==================================Service
@Service("simpleService")
public class SimpleServiceImpl implements SimpleService {
    @Autowired
    private SimpleDao simpleDao;
}
//===================================Repository
@Repository("simpleDao")
public class SimpleDaoImpl implements SimpleDao {
}

 

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工厂就不会晕了。看过上一篇博客(

<think>嗯,用户之前问过注解是什么,现在接着问Spring中的几个具体注解,看来他们对Java注解已经有了基本了解,现在想深入Spring框架的部分。我需要先确认用户的需求是什么,可能是刚开始学习Spring,或者在做项目时遇到了这些注解需要理解。 首先,用户提到的三个注解是Spring MVC和依赖注入中的核心,所以应该分别解释每个注解的作用、用法以及常见场景。比如,@Controller用于标记MVC中的控制器,@Autowired用于自动装配依赖,@RequestMapping用于映射HTTP请求到处理方法。需要确保解释清晰,同时结合例子,这样用户更容易理解。 然后,要注意用户可能的实际应用场景。比如,他们可能在搭建一个Web应用,使用Spring Boot,所以需要强调这些注解在Web开发中的重要性。此外,用户可能对如何正确使用这些注解有疑问,比如@Autowired的注入方式,或者@RequestMapping的路径配置,需要涵盖这些细节。 还要注意用户可能的误区。比如,@Autowired默认按类型注入,如果有多个同类型的Bean会报错,这时候可以用@Qualifier来指定名称。或者@RequestMapping的路径冲突问题,需要提醒他们正确配置路径和方法类型(GET、POST等)。另外,@Controller和@RestController的区别也是一个常见的混淆点,可能需要简要说明。 另外,用户可能想知道这些注解背后的原理,比如Spring如何扫描和处理这些注解,但根据之前的问题,用户可能更关注使用方式而非底层机制,所以保持解释在应用层面,适当提及原理即可,比如提到组件扫描和依赖注入的过程。 最后,需要检查是否有遗漏的重要点。比如,@Controller@Service、@Repository等其他组件注解的区别,或者@Autowired在不同版本的Spring中的变化(比如构造器注入的推荐方式)。同时,可能给出一些最佳实践,比如推荐使用构造器注入而非字段注入,以提高可测试性和避免循环依赖。 总结下来,回答结构应该分三个主要部分,每个注解详细说明,然后对比和补充常见问题,最后总结应用场景和最佳实践。确保语言简洁,例子明了,帮助用户快速掌握这三个注解的用法和注意事项。</think>好的!在 Spring 框架中,`@Controller`、`@Autowired` 和 `@RequestMapping` 是三个核心注解,分别用于实现 **Web 请求处理** 和 **依赖注入**。以下是它们的详细说明: --- ### **1. `@Controller`** - **作用**: 标记一个类为 Spring MVC 的 **控制器(Controller)**,用于处理 HTTP 请求并返回视图(如 HTML)或数据(结合 `@ResponseBody` 使用)。 - **使用场景**: - 在 MVC 模式中,负责接收请求、调用业务逻辑、返回响应。 - 通常与 `@RequestMapping` 结合,定义请求映射路径。 ```java @Controller public class UserController { // 处理 GET 请求,返回视图(如 user.html) @RequestMapping("/user") public String getUserPage() { return "user"; } } ``` --- ### **2. `@Autowired`** - **作用**: 实现 **依赖注入(Dependency Injection, DI)**,自动将 Spring 容器中的 Bean 注入到目标对象中(如字段、构造方法、Setter 方法)。 - **使用场景**: - 注入 Service 层的对象到 Controller 中。 - 自动装配数据库操作组件(如 `JpaRepository`)。 ```java @Controller public class UserController { // 自动注入 UserService 的实例 @Autowired private UserService userService; // 也可以注入到构造方法中(推荐方式,避免循环依赖) @Autowired public UserController(UserService userService) { this.userService = userService; } } ``` - **注意事项**: - 默认按 **类型(ByType)** 注入,若存在多个同类型 Bean,需结合 `@Qualifier` 指定名称。 - 如果找不到匹配的 Bean,会抛出异常(可通过 `required = false` 关闭强制依赖)。 --- ### **3. `@RequestMapping`** - **作用**: 将 HTTP 请求(如 GET/POST)映射到具体的控制器方法,并指定 **请求路径**、**方法类型**、**请求参数**等。 - **简化注解**: Spring 4.3+ 提供了更简洁的注解(如 `@GetMapping`、`@PostMapping`)。 ```java @Controller public class UserController { // 处理 GET 请求 /users,返回视图 @RequestMapping(value = "/users", method = RequestMethod.GET) public String listUsers(Model model) { model.addAttribute("users", userService.getAllUsers()); return "userList"; } // 处理 POST 请求 /user/add @PostMapping("/user/add") public String addUser(User user) { userService.saveUser(user); return "redirect:/users"; } } ``` - **关键属性**: | 属性 | 说明 | |--| | `value` / `path` | 请求路径(如 `"/user"`) | | `method` | HTTP 方法类型(如 `RequestMethod.GET`) | | `params` | 限制请求参数(如 `params = "name=admin"`) | | `headers` | 限制请求头(如 `headers = "Content-Type=application/json"`) | --- ### **组合使用示例** ```java @Controller @RequestMapping("/api") // 类级别路径,所有方法路径前加 /api public class ApiController { @Autowired private DataService dataService; // 处理 GET /api/data?id=123 @GetMapping("/data") @ResponseBody // 直接返回数据(如 JSON) public Data getData(@RequestParam("id") String id) { return dataService.findById(id); } } ``` --- ### **常见问题与技巧** 1. **`@Controller` vs `@RestController`** - `@Controller` 默认返回视图名称,需配合 `@ResponseBody` 返回数据。 - `@RestController`(= `@Controller` + `@ResponseBody`)直接返回 JSON/XML 数据,用于 RESTful API。 2. **`@Autowired` 注入方式** - **字段注入**:简单但不利于测试(需反射)。 - **构造器注入**:推荐方式(避免循环依赖,强制依赖明确)。 - **Setter 注入**:灵活性高,适用于可选依赖。 3. **路径冲突与优先级** - 更具体的路径优先匹配(如 `/user/add` 优先于 `/user/{id}`)。 4. **参数绑定** - 使用 `@RequestParam` 绑定请求参数,`@PathVariable` 绑定 URL 路径变量: ```java @GetMapping("/user/{id}") public String getUser(@PathVariable Long id, @RequestParam String name) { ... } ``` --- ### **总结** - **`@Controller`**:定义 Web 请求的入口。 - **`@Autowired`**:实现依赖注入,解耦组件。 - **`@RequestMapping`**:灵活配置请求映射规则。 这三个注解是 Spring MVC 和依赖注入的核心,掌握它们能快速构建 Web 应用和 RESTful 服务。如果具体场景(如 REST API、参数校验)需要进一步展开,可以继续提问 😊
评论 16
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寒-江

谢谢你的咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值