首页 > 其他分享 >面试官:Spring Boot 控制层中,@Service 可以完全替代 @Controller 吗?90% 都会答错!

面试官:Spring Boot 控制层中,@Service 可以完全替代 @Controller 吗?90% 都会答错!

时间:2024-10-30 09:12:48浏览次数:3  
标签:面试官 请求 Service 答错 Spring Controller 注解 SpringBoot

作者:毅航
来源:juejin.cn/post/7393533304505204787

在SpringBoot开发中,@Controller@Service基本上是日常开发中使用的最频繁的两个注解。但你有没考虑过@Service代替@Controller注解来标注到控制层的场景?换言之,经过@Service标注的控制层能否实现将用户请求分发到服务层的功能?

前言

在SpringBoot开发中,@Controller注解用于标识一个控制器类,该类负责处理Web请求。而控制器类通常包含若干个方法,每个方法对应一个HTTP请求的处理逻辑。而控制器是MVC(Model-View-Controller)架构的一部分,其主要负责将用户请求分发到适当的服务层,并返回视图或响应数据。而@Service注解用于标识一个服务类,用以负责处理业务逻辑和与数据访问层交互。

相信对于大多数Java开发者来说@Controller@Service注解的使用都不算太难。但进一步,用@Service标注控制层能否达到和@Controller注解相同的功能呢?对于这个操作你可能会觉得很疯狂,并下意识的说出不可能。但事实果真如此吗?

我们不妨先通过一个简单的例子来验证一下。

@Sercice代替@Controller

我们首先自定义一个ServiceController的控制层,其内部通过Autowired注解注入一个UserMapper,并通过userMapper来实现控制层与数据层的交互。

Spring Boot 基础就不介绍了,推荐看这个实战项目:

https://github.com/javastacks/spring-boot-best-practice

具体代码如下:

ServiceController
@Service
@RequestMapping("/ts")
public class ServiceController {

    @Autowired
    private UserMapper userMapper;

    @GetMapping("get-services")
    @ResponseBody
    public User getServices() {
        User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getUsername, "zhangSan"));
        return user;
    }
}

然后,通过PostMan发送一个Get请求,以请求 http://localhost:8080/ts/get-services 其返回内容如下 :

Date: Sun, 21 Jul 2024 02:37:39 GMT
Keep-Alive: timeout=60
Connection: keep-alive

{
  "username": "zhangSan",
  "id": 1,
  "type": null,
  "remark": "test1"
}

通过返回内容,不难看出我们的请求顺利到ServiceControllergetServices方法。也就是说我们完全可以用@Service来替代@Controller标注在控制层上!

揭秘背后原理

你可能会觉得@Service来替代@Controller这样的操作有的反常规,因为在学习SpringBoot时,从来也没有那个教程告诉我们@Service注解还有这样的骚操作。那@Service可以这样使用的背后原因到底是什么呢?

众所周知,@Service@Controller注解都能被Spring容器所加载,并注入到Spring容器中。我们以SpringBoot应用为例来分析其注入容器的全过程。

在分析之前我们首先明确一点,对于Spring而言其会根据配置(如 XML 文件或 @ComponentScan 注解)扫描指定的包及其子包,查找标记有 @Controller@Service@Repository@Component 的类。但对于Springboot应用而言,其并没有显示的使用XmL配置或@ComponentScan指定扫描路径的方式来加载对应路径下的Bean信息。

这背后的原因主要在于@SpringBootApplication 注解的使用,@SpringBootApplication其实是一个组合注解,其内部包括以下三个注解:

  • @EnableAutoConfiguration: 启用 Spring Boot 的自动配置机制。
  • @ComponentScan: 启用组件扫描,以便自动发现并注册 Spring 组件。
  • @Configuration: 表示这是一个 Spring 配置类。

在默认情况下,Spring Boot 会从主应用类所在的包开始进行组件扫描,这意味着只要 @Controller@Service 注解的类位于主应用类所在包及其子包中,它们就会被自动发现并注册到 Spring 容器中。

明白了SpringBoot对于Bean的加载逻辑后,我们再来深入到其内部来看。SpringBoot对于这部分Bean的加载流程如图所示:

当我们在main方法中执行SpringApplication.run时,其在run方法内容会完成Spring容器的创建,以及Bean的加载。具体来看,其在AbstractApplicationContext中的invokeBeanPostBeanFactoryPostProcessore时,会通过 ConfigurationClassPostProcessorpostProcessBeanDefinitionRegistry 方法加载路径下所有的bean名称信息,然后在finshBeanFactoryInitialization完成bean的实例化。而我们绕了这么一大圈就是皆在说明,被@Service@Controller所标注的类在SpringBoot框架中是如何一步步被注入到容器的。

进一步,笔者曾在揭秘@Controller内部方法与URL绑定的全流程中谈到,对于控制层内的方法,其会在AbstractHandlerMethodMapping中的 afterPropertiesSet()完成请求url与方法的映射绑定。更进一步,afterPropertiesSet的处理逻辑全部委托于于 getCandidateBeanNamesprocessCandidateBean两个方法。

getCandidateBeanNames 会获取当前容器中所有的bean 的名称集合,并筛选类中标有@Controller或者 @RequestMapping注解的类交给processCandidateBean处理,以完成请求url与方法的映射。

此时,我们不妨来回看我们一开始的ServiceController的样例代码:

@Service
@RequestMapping("/ts")
public class ServiceController {

   // ....省略内部细节信息
}

不难发现,其虽然没使用@Controller修饰,但其却被@RequestMapping注解信息,也就是说其能被processCandidateBean所处理,进而其也就能完成url和方法映射关系的维护。更进一步,当请求至DispatcherServlet时,SpringMVC变更通过其url信息,找到能处理相应请求的HandlerMethod。从而也就能完成url的处理以及视图的渲染。

事实上,只要你能确保Bean信息注入到容器,并且类信息上至少有@Controller或者 @RequestMapping注解,那便能在AbstractHandlerMethodMapping中所解析,然后完成url与方法的绑定!这也就是为什么我们一开始花费精力研究@Controller@Service 注入容器的原因。

总结

在 SpringBoot 开发中,@Controller@Service 是最常用的注解。通常,@Controller 用于标识控制器类,处理 Web 请求并将请求分发到服务层;而 @Service 用于标识服务类,处理业务逻辑。然而,如果用 @Service 来标注控制层是否可以实现与 @Controller 相同的功能呢?

答案是肯定的。只要类被 @Service 标注,并且包含 @RequestMapping 等注解,Spring Boot 依然能够将其作为控制器来处理请求并返回响应。这背后的原理在于 @Service@Controller 都能被 Spring 容器加载和注册,并且 @RequestMapping 注解能够使类的方法与 URL 映射,从而实现请求处理功能。

更多文章推荐:

1.Spring Boot 3.x 教程,太全了!

2.2,000+ 道 Java面试题及答案整理(2024最新版)

3.免费获取 IDEA 激活码的 7 种方式(2024最新版)

觉得不错,别忘了随手点赞+转发哦!

标签:面试官,请求,Service,答错,Spring,Controller,注解,SpringBoot
From: https://www.cnblogs.com/javastack/p/18514946

相关文章

  • 【Azure Bot Service】部署Python ChatBot代码到App Service中
    问题描述使用Python编写了ChatBot,在部署到AppService,却无法启动。通过高级工具(Kudu站点:https://<yoursitename>.scm.chinacloudsites.cn/newui)查看日志显示:Failedtofindattribute'app'in'app'.2024-10-25T02:43:29.242073529Z_____......
  • 面试官:自定义Loader和Plugin实现过吗?
    Loader案例:多语言翻译Loader这个自定义Loader旨在支持多语言翻译功能。在项目开发中,文本字符串通常会放在一个JSON文件中,如 en.json 和 zh.json,分别用于存储不同语言的文本。自定义Loader可以在编译过程中将代码中的特定标记(如 __t('KEY'))替换为对应语言的字符串,......
  • 新接口0day全程云DocumentDocService.asmx接口存在任意文件上传漏洞
     0x01阅读须知        技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用......
  • # MySQL 三万字精华总结 + 面试100 问,和面试官扯皮绰绰有余
    MySQL三万字精华总结+面试100问,和面试官扯皮绰绰有余写在之前:不建议那种上来就是各种面试题罗列,然后背书式的去记忆,对技术的提升帮助很小,对正经面试也没什么帮助,有点东西的面试官深挖下就懵逼了。个人建议把面试题看作是费曼学习法中的回顾、简化的环节,准备面试的......
  • k8s部署metallb实现service的LoadBalancer模式
    开启ipvs并开启严格ARP模式参考https://metallb.io/installation/kubectleditconfigmap-nkube-systemkube-proxy源mode:""ipvs:strictARP:false改成mode:"ipvs"ipvs:strictARP:truek8s原生部署metallb下载wgethttps://raw.githubus......
  • 如何使用Service Workers_1
    使用ServiceWorkers的步骤:1.了解ServiceWorkers;2.检查浏览器支持;3.注册ServiceWorker;4.创建ServiceWorker文件;5.安装和激活ServiceWorker;6.拦截和处理请求;7.测试ServiceWorker等。首先,要了解ServiceWorkers是什么以及它们的作用。1.了解ServiceWorkers首先,要......
  • springboot:test类中的UserService无法自动装配,解决方案
    检查Service类遇到这种问题一般先检查你的Service是否有bean即有无用@Service注释,或者有无其他service的bean配置漏了在这里是已经有注释了那么可能就是spring启动的时候没有识别到我的bean检查启动文件在扫描路径中少了我的service包所在的路径packagecom.tutor......
  • IDEA 微服务,配置services菜单管理服务启动和调试
    打开工程下的workspace配置RunDashboard<componentname="RunDashboard"><optionname="configurationTypes"><set><optionvalue="SpringBootApplicationConfigurationType"/></set>......
  • 异步&线程池【CompletableFuture&ExecutorService】
    Gulimall一、异步&线程池【ExecutorService】异步场景:为了节约时间和提高系统吞吐量做一些异步任务。异步在java中一般是使用Thread开启一个线程的方式;一、线程池线程池(ThreadPool),是一种基于池化思想的管理线程的工具,可以实现线程的复用,避免线程使用中频繁创建和......
  • Ubuntu问题:Unit network-manager.service not found.
    问题描述使用network-manager相关命令,如sudoservicenetwork-managerstop、sudoservicenetwork-managerstart等发生报错。Ubuntu右上角网络图标消失解决方法Ubuntu20.*版本貌似20.*版本以后network-manager变成了NetworkManager,因此,只要把命令中的network-ma......