SpringBoot项目中如何定制HTTP消息转换器?

要想自己定制HTTP消息转换器必须先知道SpringBoot默认是怎么做HTTP消息转换的。

先来看我们平常工作中开发一个简单的get请求:

SpringBoot项目中如何定制HTTP消息转换器?那么当前端请求我们的API的时候,我们是如何将网络传输的字节流序列化成我们想要的对象呢?做完业务处理后又是如何返回数据呢?

HttpMessageConverter

在SpringBoot框架下,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换,底层这种灵活的消息转换机制,就是Spring3.x中新引入的HttpMessageConverter即消息转换器机制。

SpringBoot项目中如何定制HTTP消息转换器?

打开任何一个集成了Spring-web功能的SpringBoot项目,都可以找到这个HttpMessageConvert:

SpringBoot项目中如何定制HTTP消息转换器?

可以看到他是一个接口类,和他在一个包下面有很多实现类,感兴趣的同学可以debug跟进去把这块源码搞透,这个过程中大家还可以学习到很多关于序列化的知识。

源码解析:怎么知道SpringBoot中的默认convert

在项目的启动类Application.class上有一个@SpringBootApplication注解,点进去会看到他是一系列注解的包含,其中有一个@EnableAutoConfiguration注解,继续点进去查看:

SpringBoot项目中如何定制HTTP消息转换器?

发现引入了一个类:AutoConfigurationImportSelector类,继续跟进去有一个方法selectImports():

SpringBoot项目中如何定制HTTP消息转换器?

继续点击进入loadMetadata这个方法:

SpringBoot项目中如何定制HTTP消息转换器?

到这一步相信大家就清晰了他是怎么加载的了:

SpringBoot项目中如何定制HTTP消息转换器?

继续走下去就知道如何加载消息的默认convert,这里就不和大家说答案,希望大家自己可以跟进去看看,收获是不一样的~

定制自己的convert

知道了消息转换器的原理以及SpringBoot中如何加载的,我们就知道如何去定制自己的消息转换器了,先实现自己的一个convert,继承AbstractHttpMessageConverter:

SpringBoot项目中如何定制HTTP消息转换器?

然后定义一个WebConfig类继承WebMvcConfigurer,把我们自定义的这个convert加进去:

SpringBoot项目中如何定制HTTP消息转换器?

实际工作中,大家可能很多时候并不需要自己去实现convert,用默认的消息转换器就可以了,除非大家有自己特殊的需求考虑,否则不建议非得自己去实现这个convert。


以上就是关于SpringBoot中如何定制消息转换器的回答了,不足之处欢迎大家评论交流,共同学习。

我是【java架构设计】,如果我的回答对您有帮助,欢迎转发点赞,我将持续为您提供Java领域优质内容!

如何系统的学习Spring?正确的阅读源码姿势?

如何系统的学习Spring,以我15年J2EE教学和开发经验来说,首先要清楚Spring的概念和特性,以及在JavaEE框架中起到的作用。在此基础上再开展学习。(欢迎转发)

(1) Spring概念

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架

目的:解决企业应用开发的复杂性

功能:使用基本的JavaBean代替EJB,确保开发的简单性、可测试性和松耦合性;同时提供更多的企业应用功能

范围: Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益

(2)Spring特性

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。不管是SSH,还是SSM,都是由Spring通过IOC和AOP来对对象和对象组装关系进行统一管理。所以学好Spring,就是要学好IOC和AOP。看代码,看Spring源码,都是以这两者为核心。

轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类和接口。

控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。

面向切面——Spring提供了面向切面编程(AOP)的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如权限、日志和事务管理等)进行内聚性的开发。应用对象只实现它们应该完成的业务功能,不考虑其它的系统级关注点,例如日志或事务支持。

容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,可以配置每个bean如何被创建(bean可以创建一个单独的实例或者每次需要时都生成一个新的实例),以及它们是如何相互关联的。

框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。

(3)Spring带来了复杂的J2EE框架开发的春天。

Spring具有如下优点:

低侵入式设计,代码的污染度低;

独立于各种应用服务器,基于Spring框架的应用,可以真正实现Write Once,Run Anywhere;

Spring的IoC容器降低了业务对象的耦合性;

Spring的AOP支持允许将一些通用的功能(权限、事务、日志等)等集中处理,提升了复用性,同时让开发者集中精力于业务功能的处理实现;

Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问;

Spring是高度开放的,开发者可以自由选择Spring框架的部分或全部。

(4)目前最流行的Java EE开发框架是SSM,这时就需要以Spring为核心配置与管理工具,掌握spring和spring-mvc进行整合,Spring和mybatis进行整合与配置的方法。才能从容进行基于SSM的Java EE项目的开发。

(5)SpringBoot

目前很火的SpringBoot也是以Spring为基础,它是主要面向web服务,也就是微服务开发的。这个又是另外一个话题了。先学好Spring没错的。

刘嵩

2020.5.19

我是一名大一学生,自学了springboot并搭建了微服务,现在我打算先从底层学起,应该学什么比较好?

能在大一就可以搭建起SpringBoot,那说明你还是具有一定的编程基础的。题主所说的想从底层学起,说明题主可能只是按照SpringBoot教程跑通了简单的SpringBoot Demo,这离成为一名优秀的Java工程师还有很长的一段距离。那要想成为一名优秀的Java工程师,我们还需要学习那些”底层“知识呢?

SpringBoot项目中如何定制HTTP消息转换器?

1、工具

工具分为两个部分,开发工具和项目构建工具。开发工具IDE帮助我们编译、运行、调试、分析、测试代码等等,我比较喜欢IntelliJ IDEA。构建工具用来构建和部署项目,例如maven、gradle和ant。Ant已经没落了,很少有java项目中使用,Maven使用的比较多,但是Maven基于xml语法比较死板,我比较喜欢gradle,推荐大家使用gradle。

SpringBoot项目中如何定制HTTP消息转换器?

2、JDK API

JDK API对于开发人员来说非常重要,这是很大的一部分内容。包括Java Collections框架,Java Concurrency,Java IO和Java 8 API等核心领域。

  • 2.1 Java集合框架

这是每个Java开发人员都应该学习的最重要的Java API之一。该API提供了Java中标准数据结构的实现,例如链表,集合,堆栈,队列,哈希表,优先级队列等。

我们对于ArrayList、HashMap、HashSet、LinkedHashSet、TreeSet等框架必须要精通掌握,并知道它们的内部实现逻辑。例如, ArrayList是一个可以增长的动态数组,HashMap 是哈希表的标准实现,可以用于存储键值对。同样,HashSet是一个不允许重复元素的set实现。

SpringBoot项目中如何定制HTTP消息转换器?

  • 2.2 java并发

多线程和并发是一个合格的java工程师必须掌握的。我们不仅应该深入了解诸如Thread、Runnable对象锁定和同步之类的基本概念,而且还应该熟悉诸如死锁,乐观锁,condition以及如何使用它们。同时也应该了解像Java5中及以后的版本,例如CyclicBarrier、CountDownLatch、Phaser、CompleteableFuture、Futures等等特性以及如何在Java中执行异步操作。

SpringBoot项目中如何定制HTTP消息转换器?

  • 2.3 Java io

Java IO 和NIO API平常开发可能用的比较少,但是对于File、InputStream、OutputStream、Reader以及Writer这些核心API我们要精通掌握。同时如果我们需要编写一个基于套接字的的程序,对于ByteBuffer、FileChannel、Selector也必须掌握。

SpringBoot项目中如何定制HTTP消息转换器?

  • 2.4 Java 8新特性

Java8 改变了我们以往的编码和编码方式,以前需要写10行代码才能完成的功能,现在可能只需要几行。Lambda表达式、Stream API、Optional类和新的DateTime API,这些我们都应该熟练掌握。

SpringBoot项目中如何定制HTTP消息转换器?

3、框架

Java生态中有丰富的框架可以供开发者使用。对于主流的框架我们要有一定的了解。例如:Spring、SpringMVC、SpringBoot、Hibernate、Log4j、Mybatis、JUnit等。

  • 3.1 Spring Framework

如果您想成为优秀的Java开发人员,强烈建议首先学习Spring Framework。这是最流行的Java框架之一。Spring Framework使开发人员能够编写干净的代码,通过依赖注入和控制反转等功能可以更轻松地测试和维护代码。它还具有用于大多数日常任务的丰富API。

SpringBoot项目中如何定制HTTP消息转换器?

  • 3.2 Mybatis

早期ORM框架比较火的是Hibernate。但是Hibernate限制太多,特别是在复杂业务场景下无能为力。Mybatis是目前最流行的ORM框架。支持灵活的sql、存储过程以及高级映射。MyBatis 可以使用简单的XML或注解来配置和映射原生类型、接口和 Java 的 POJO为数据库中的记录。

SpringBoot项目中如何定制HTTP消息转换器?

  • 3.3 SpringBoot

SpringBoot应该是目前最火的MVC框架了,SpringBoot将程序员从繁重的XML配置中解放了出来。在没有SpringBoot的时代,我们编写一个后端的web应用,需要大量的xml配置。SpringBoot的出现使创建基于Spring的Java应用程序变得非常容易。你只需要2分钟就可以出创建一个应用并将它跑起来,这极大的提升了程序员的工作效率,使得程序员可以更专注业务代码实现。

SpringBoot项目中如何定制HTTP消息转换器?

4、测试

测试是任何Java开发人员的一项基本技能,尤其是单元测试,集成测试和自动化测试。至少,每个Java开发人员都应该熟悉JUnit和Mockito,这是两种最受欢迎的单元测试和模拟库。如果您知道这两个并知道如何使用它们来有效地创建单元测试,那你将是一个更好的Java开发人员。还存在更高级的库,例如用于业务驱动测试的Cucumber,用于集成测试的Robot Framework。对于模拟库,开发人员可以选择PowerMock,Mockito和EasyMock等几种选择,但我强烈建议学习Mockito,因为它是一个很棒的库,并且许多Java开发人员和公司都在使用它。它正逐渐成为在Java中创建模拟对象的标准库。

SpringBoot项目中如何定制HTTP消息转换器?

5、常用的库

Java的真正功能在于其丰富的开源库生态系统。你会发现库在Java中几乎可以完成所有工作,从日志记录到机器学习,从发送HTTP请求到解析JSON等等。

除此之外,Java还幸运地拥有诸如Apache Commons和Google Guava之类的实用程序库。这两个库有效地补充了JDK库。

最后

如果你已经掌握了这其中一半以上的技术,那恭喜你,你算得上以为优秀的java工程师。如果没有,那好好学习这些技术,它就伴随这你以后职业生涯。当然计算机原理、数据结构、数据库理论等课程将是你大二、大三的专业课,这些课程必须好好学习,深入掌握。

该如何学习spring源码以及解析bean定义的注册?

!我将从以下几点介绍源码及Spring是怎样解析Bean定义并注册的

目录:

  1. 学习源码的重要性?

  2. 学习Spring源码需要基础吗?

  3. 怎样把Spring源码在本地运行?

  4. Bean定义的加载过程

  5. bean定义加载的流程图

  6. 总结

学习源码的重要性?

(1) 可以提升技术功底,Spring源码也沉淀了很多年,有非常多的精华所在,不管我们什么水平,通过不断的阅读源码,能对我们的技术有很大的提升,并且工作中遇到类似问题的时候,可以借鉴源码中是怎么处理的。

(2) 深度的掌握技术框架:源码看多了,对于新的框架的学习和掌握都是很快的,看下框架的demo,就知道底层是怎么实现的。

比如,学习了Spring 中的AOP,就知道底层是用了JDK的动态代理。然后我们学习mybatis的时候,就在想Mybatis 为什么Service可以直接嗲用Dao接口,就可以直接查询数据库了呢 ?其实也是Spring底层对给接口做了动态代理。

(3) 对线上的问题可以进行快速的定位: 当生产上遇到问题时,能够快速的进行定位,这个能力可以快速秒杀别人。

(4) 对面试有很大的好处,特别是BAT大厂,一般都是问道源码级别的,你如果不会,可能第一轮就会被刷掉。

学习Spring源码需要基础吗?

答案是肯定的,需要,那么需要哪些基础呢?

(1)Java 的技术功能

(2) 反射

(3) 设计模式: 简单工厂、工厂方法、单例模式、原型模式、代理模式、策略模式、模板方法模式、委派模式、适配器模式、装饰器模式、观察者模式

(4) Lambda表达式的知识

怎样把Spring源码在本地运行?

(1) git clone https://github.com/spring-projects/spring-framework.git

SpringBoot项目中如何定制HTTP消息转换器?

(2) gradle下载,gradle需要JDK8版本

(3) 到下载的spring源码路径执行gradle命令,gradlew :spring-oxm:compileTestJava

(4) 用idea打开spring源码工程,在idea中安装插件kotlin,重启idea

(5) 把编译好的源码导入到工程中

Bean定义的加载过程

1、首先找到程序的入口

① 找到其构造方法:

SpringBoot项目中如何定制HTTP消息转换器?

② 调用 AnnotationConfigApplicationContext 构造方法,最终会调用父类 GenericApplicationContext的无参方法

SpringBoot项目中如何定制HTTP消息转换器?

③ 调用父类 AnnotationConfigApplicationContext 无参构造方法,生成bean定义读取器和Bean定义扫描器

SpringBoot项目中如何定制HTTP消息转换器?

上面方法的功能是: 实例化注解的Bean定义扫描器,定义类类路径下的bean定义扫描器

3.1 为Bean定义读取器赋值

SpringBoot项目中如何定制HTTP消息转换器?

3.1.1 为容器 中注册系统的Bean定义信息

SpringBoot项目中如何定制HTTP消息转换器?

SpringBoot项目中如何定制HTTP消息转换器?

上面代码主要是注册系统的Bean定义信息,包含以下几种:

① ConfigurationClassPostProcessor

是一个BeanFactory的后置处理器,主要功能是参与BeanFactory的构建,在这个类中,会解析@Configuration的配置类,解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import等注解。

② AutowiredAnnotationBeanPostProcessor

AutowiredAnnotationBeanPostProcessor 实现了BeanPostProcessor,当Spring容器启动的时候,AutowiredAnnotationBeanPostProcessor 将扫描Spring容器中的所有Bean,当发现Bean中拥有

@Autowired 注解的时候就会找到与其匹配的Bean,并注入到对应的中去。

那么在什么时候调用的呢?我们可以看下debug堆栈;

SpringBoot项目中如何定制HTTP消息转换器?

③ RequiredAnnotationBeanPostProcessor

RequiredAnnotationBeanPostProcessor 是BeanPostProcessor实现.的,注释应用于bean属性的setter方法,它表明 受影响的bean 属性在配置时是否必须,如果配置了,没有此bean,则容器就会抛出一个BeanInitializationException 异常。

④ .CommonAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor 这个BeanPostProcessor 通过继承 InitDestroyAnnotationBeanPostProcessor 对 @PostConstruct 和 @PreDestroy注解的支持,以及对bean的依赖注入@Resource的支持。

⑤ EventListenerMethodProcessor

使用EventListenerMethodProcessor处理器来解析方法上的 @EventListener;

执行时机: 实在所有Bean都实例化以后执行的

SpringBoot项目中如何定制HTTP消息转换器?

④ 创建类路径下的bean定义扫描器

SpringBoot项目中如何定制HTTP消息转换器?

上述方法 是注册默认的扫描规则

⑤ 读取配置类

SpringBoot项目中如何定制HTTP消息转换器?

上述方法annotatedClasses为我们配置的mainConfig

SpringBoot项目中如何定制HTTP消息转换器?

annotatedClasses 就是MainConfig

SpringBoot项目中如何定制HTTP消息转换器?

此时上面主要解析 MainConfig,解析成BeanDefinition对象

SpringBoot项目中如何定制HTTP消息转换器?上述的字段都是什么意思呢?

  1. id: Bean的唯一标识名
  2. name: 用来为id 创建一个或者多个别名。
  3. class : 用来定义类的全限定名(包名 + 类名)
  4. parent: 子类bean定义它所引用它的父类的bean。
  5. abstract : 默认为false,用来定义bean是否为抽象bean,它表示这个Bean将不会被实例化,一般用于父类Bean,因为父类bean主要供子类bean继承使用。
  6. lazy-init: 用来定义这个bean是否实现懒初始化。如果为true,它将在BeanFactory启动时初始化所有的单例bean,反之,如果为false,它只在Bean请求使用时才开始创建SingletonBean。
  7. autowired : 自动装配,它定义了Bean 的自动装配方式。
  8. depends-on:依赖对象:这个Bean在初始化时依赖的对象,这个对象会在这个Bean初始化之前创建。
  9. init-method: 用来定义Bean的初始化方法,它会在Bean组装之后调用,它必须是一个无参的构造 方法。
  10. destroy-method: 用来定义Bean的销毁方法,它在BeanFactory关闭时调用。同样,它也必须是一个无参 的构造方法。只能适用于单例Bean.
  11. factory-method: 定义创建该Bean对象的 工厂方法。
  12. factory-bean:定义创建该 Bean对象的工厂类。

那么 BeanDefinitionHolder 又是什么意思呢?

SpringBoot项目中如何定制HTTP消息转换器?

BeanDefinitionHolder 只是封装了BeanDefinition对象,并且添加了beanName 和 alias 属性。

为什么这样设计呢?因为 我们定义bean时,可以定义多个别名的。

BeanDefinitionRegistry 又是什么呢?

SpringBoot项目中如何定制HTTP消息转换器?

BeanDefintion属性来看,我们并没有看到id 和 name属性没有体现在定义中,原因是ID其左右当前Bean的存储key注册到BeanDefinitionRegistry注册器中。name作为别名key注册到AliasRegistry注册中心。最后都是指向其对应的BeanDefinition。

2、AnnotatedBeanDefinitionReader(Bean定义读取)

BeanDefinition 中存储了Bean的信息,而BeanDefintiionRegistry是基于ID和name保存了Bean的定义。从Bean到BeanDefinition然后再注册到BeanDefintionRegistry整个过程。

SpringBoot项目中如何定制HTTP消息转换器?

从上图看出Bean的定义是由AnnotatedBeanDefinitionReader从@Bean的注解中构建出的,然后基于别名注册到BeanDefinitionRegistry。

BeanDefintionReader 的结构图如下:

SpringBoot项目中如何定制HTTP消息转换器?

2.1 bean定义的加载过程

(1) org.springframework.context.support.AbstractApplicationContext#refresh

注册Bean的 代码

invokeBeanFactoryPostProcessors(beanFactory);

(2) org.springframework.context.support.AbstractApplicationContext

#invokeBeanFactoryPostProcessors

SpringBoot项目中如何定制HTTP消息转换器?

然后实例化 容器初始化 的 ConfigurationClassPostProcessor Bean,然后调用其 的postProcessBeanDefinitionRegistry方法

BeanDefinitionRegistryPostProcessor 这个接口的调用分为三部分:

(1) 调用实现PriorityOrdered 排序接口

(2) 调用实现了Ordered排序接口

(3) 没有实现接口的调用

这个接口的理解如下: 获取BeanDefinition 对象,获取到这个对象就可以获取这个对象中注册的 所有BeanDefiniton对象,我们拥有这个对象后,我们就可以对里面所有的BeanDefinition 对象进行修改。

SpringBoot项目中如何定制HTTP消息转换器?

  1. org.springframework.context.annotation.ConfigurationClassPostProcessor

#postProcessBeanDefinitionRegistry 方法

SpringBoot项目中如何定制HTTP消息转换器?

SpringBoot项目中如何定制HTTP消息转换器?

最终调用

org.springframework.context.annotation.ConfigurationClassParser

最终调用 org.springframework.context.annotation.ConfigurationClassParser

#doProcessConfigurationClass 方法

下面方法主要功能如下:

  • 解析 @PropretySource注解
  • 解析@ComponentScan注解
  • 解析@Import
  • 解析@ImportResource
  • 解析@Bean methods
  • 处理其他

SpringBoot项目中如何定制HTTP消息转换器?

bean定义加载的流程图

SpringBoot项目中如何定制HTTP消息转换器?

总结

Spring 对注解的处理有两种方式:

1、直接将注解Bean注册到容器中

可以在初始化容器的时候注册,也可以在容器创建之后手动调用注册方法向容器中注册,然后通过手动刷新容器,使得容器对注册的注解Bean进行处理

2、通过扫描指定的 包及其子包下的所有类

在初始化注解容器的时指定要自动扫描的路径。如果容器创建以后,如果再向容器中添加注解Bean,则 需要手动调用容器扫描的方法,然后手动刷新容器,使得容器对所注册的Bean进行处理。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 xxx@163.com 举报,一经查实,本站将立刻删除。

发表评论

登录后才能评论