参考版本:2.2.0.RELEASE
启动Springboot项目
@SpringBootApplication
public class SpringbootTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootTestApplication .class, args);
}
}
1. SpringApplication.java的执行步骤
SpringApplication.java的执行步骤1
public class SpringApplication {
//第五步:初始化以下变量
private Set<String> sources = new LinkedHashSet<>();
private Banner.Mode bannerMode = Banner.Mode.CONSOLE;
private boolean logStartupInfo = true;
private boolean addCommandLineProperties = true;
private boolean addConversionService = true;
private boolean headless = true;
private boolean registerShutdownHook = true;
private Set<String> additionalProfiles = new HashSet<>();
private boolean isCustomEnvironment = false;
//第三步
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
//第四步(未进入构造中)
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//第六步
// 1、初始化资源加载器
this.resourceLoader = resourceLoader;
// 2、断言主要加载资源类不能为 null,否则报错
Assert.notNull(primarySources, "PrimarySources must not be null");
// 3、初始化主要加载资源类集合并去重
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 4、推断当前 WEB 应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 5、设置应用上线文初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 6、设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 7、推断主入口应用类
this.mainApplicationClass = deduceMainApplicationClass();
}
//第一步:加载静态配置上下文
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
//第二步: 加载静态配置上下文
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
//第七步:
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
// 秒表,用于记录启动时间;记录每个任务的时间,最后会输出每个任务的总费时
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// spring应用上下文,也就是我们所说的spring根容器
ConfigurableApplicationContext context = null;
// 自定义SpringApplication启动错误的回调接口
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 设置jdk系统属性java.awt.headless,默认情况为true即开启;关于java.awt.headless查看备注
configureHeadlessProperty();
// 获取启动时监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 触发启动事件,相应的监听器会被调用,这是本文重点
listeners.starting();
try {
// 参数封装,也就是在命令行下启动应用带的参数,如--server.port=9000
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境:1、加载外部化配置的资源到environment;2、触发ApplicationEnvironmentPreparedEvent事件
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 配置spring.beaninfo.ignore,并添加到名叫systemProperties的PropertySource中;默认为true即开启
configureIgnoreBeanInfo(environment);
// 打印banner图
Banner printedBanner = printBanner(environment);
// 创建应用上下文,并实例化了其三个属性:reader、scanner和beanFactory
context = createApplicationContext();
// 获取异常报道器,即加载spring.factories中的SpringBootExceptionReporter实现类
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 准备上下文
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
}
备注注:Headless模式是在缺少显示屏、键盘或者鼠标是的系统配置。在java.awt.toolkit和java.awt.graphicsenvironment类中有许多方法,除了对字体、图形和打印的操作外还可以调用显示器、键盘和鼠标的方法。但是有一些类中,比如Canvas和Panel,可以在headless模式下执行。2
启动方法解析监听器
// 获取启动时监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 触发启动事件,相应的监听器会被调用,这是本文重点
listeners.starting();
SpringApplicationRunListeners:这个类是SpringApplicationRunListener的一个集合
class SpringApplicationRunListeners {
private final Log log;
private final List<SpringApplicationRunListener> listeners;
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {//listeners为EventPublishingRunListener
listener.starting();
}
}
}
EventPublishingRunListener.java
EventPublishingRunListener:继承了SpringApplicationRunListener,使用初始化好的事件广播器广播Application启动事件,这个类的接口实现主要有initialMulticaster来完成—装饰器模式
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
@Override
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
}
接下来看是如果广播事件的:spring中的事件监控–观察者模式
SimpleApplicationEventMulticaster.java
SimpleApplicationEventMulticaster:是接口ApplicationEventMulticaster的一个简单实现类,将所有的事件广播给所有的监听器,每个监听器只关心自己要监听的事件,不关心的就会忽略。默认在调用(当前)的线程中调用监听器,如果定义了线程池就会在新的线程中调用。
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {//监听到的事件
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));//这个位置执行了以下监听器
}
else {
invokeListener(listener, event);
}
}
}
}
从代码getApplicationListeners(event, type)的结果来看,有以下监听器都监听了ApplicationStartingEvent,接下来每种监听器逐个执行
过滤出与ApplicationStartingEvent匹配的监听器,过滤出的结果执行过程:
LoggingApplicationListener
ConfigFileApplicationListener
>>BackgroundPreinitializer
ConfigFileApplicationListener
DelegatingApplicationListener
SpringApplicationAdminMXBeanRegistrar
>>BackgroundPreinitializer
SpringApplicationAdminMXBeanRegistrar
SimpleApplicationEventMulticaster调用监听器的方法doInvokeListener
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);//如果是BackgroundPreinitializer监听器,到达BackgroundPreinitializer的onApplicationEvent方法
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
}
BackgroundPreinitializer:对于一些耗时的任务使用一个后台线程尽早触发它们开始执行初始化,这是Springboot的缺省行为。这些初始化动作也可以叫做预初始化。设置系统属性spring.backgroundpreinitializer.ignore为true可以禁用该机制。该机制被禁用时,相应的初始化任务会发生在前台线程。2
@Order(LoggingApplicationListener.DEFAULT_ORDER + 1)
public class BackgroundPreinitializer implements ApplicationListener<SpringApplicationEvent> {
private static final CountDownLatch preinitializationComplete = new CountDownLatch(1);
@Override
public void onApplicationEvent(SpringApplicationEvent event) {
if (!Boolean.getBoolean(IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME)
&& event instanceof ApplicationStartingEvent && preinitializationStarted.compareAndSet(false, true)) {
performPreinitialization();//初始化调用
}
if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent)
&& preinitializationStarted.get()) {
try {
preinitializationComplete.await();
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
private void performPreinitialization() {
try {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
runSafely(new ConversionServiceInitializer());
runSafely(new ValidationInitializer());
runSafely(new MessageConverterInitializer());//这里消息转换器初始化
runSafely(new MBeanFactoryInitializer());
runSafely(new JacksonInitializer());
runSafely(new CharsetInitializer());
preinitializationComplete.countDown();
}
public void runSafely(Runnable runnable) {
try {
runnable.run();
}
catch (Throwable ex) {
// Ignore
}
}
}, "background-preinit");
thread.start();
}
catch (Exception ex) {
// This will fail on GAE where creating threads is prohibited. We can safely
// continue but startup will be slightly slower as the initialization will now
// happen on the main thread.
preinitializationComplete.countDown();
}
}
/**
* Early initializer for Spring MessageConverters.
*/
private static class MessageConverterInitializer implements Runnable {
@Override
public void run() {
new AllEncompassingFormHttpMessageConverter();//执行到这里先走的父类的静态变量,然后走该类的静态代码块,然后再走到构造方法里面,调用了addPartConverter(new MappingJackson2HttpMessageConverter());
}
}
}
AllEncompassingFormHttpMessageConverter.java 所有的压缩格式
public class AllEncompassingFormHttpMessageConverter extends FormHttpMessageConverter {
private static final boolean jaxb2Present;
private static final boolean jackson2Present;
private static final boolean jackson2XmlPresent;
private static final boolean jackson2SmilePresent;
private static final boolean gsonPresent;
private static final boolean jsonbPresent;
static {
ClassLoader classLoader = AllEncompassingFormHttpMessageConverter.class.getClassLoader();
jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
}
public AllEncompassingFormHttpMessageConverter() {
try {
addPartConverter(new SourceHttpMessageConverter<>());
}
catch (Error err) {
// Ignore when no TransformerFactory implementation is available
}
if (jaxb2Present && !jackson2XmlPresent) {
addPartConverter(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
addPartConverter(new MappingJackson2HttpMessageConverter());//调用了该方法,先new MappingJackson2HttpMessageConverter()再增加到List>中
//new MappingJackson2HttpMessageConverter()先走父类AbstractJackson2HttpMessageConverter的静态常量UTF-8,再走的子类的构造
}
else if (gsonPresent) {
addPartConverter(new GsonHttpMessageConverter());
}
else if (jsonbPresent) {
addPartConverter(new JsonbHttpMessageConverter());
}
if (jackson2XmlPresent) {
addPartConverter(new MappingJackson2XmlHttpMessageConverter());//json转换xml
}
if (jackson2SmilePresent) {
addPartConverter(new MappingJackson2SmileHttpMessageConverter());
}
}
}
MappingJackson2HttpMessageConverter.java
public class MappingJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
public MappingJackson2HttpMessageConverter() {//初始化构造中开始存入媒体类型
this(Jackson2ObjectMapperBuilder.json().build());
}
public MappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));//传递了两个MediaType,一个是MediaType.APPLICATION_JSON,既是"application/json",一个是 "application/*+json"
}
}
父类AbstractJackson2HttpMessageConverter.java
public abstract class AbstractJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter<Object> {
protected AbstractJackson2HttpMessageConverter(ObjectMapper objectMapper, MediaType... supportedMediaTypes) {
this(objectMapper);
setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));//在AbstractHttpMessageConverter.java设置了支持的类型
}
AbstractGenericHttpMessageConverter.java
public abstract class AbstractGenericHttpMessageConverter<T> extends AbstractHttpMessageConverter<T>
implements GenericHttpMessageConverter<T> {
}
AbstractHttpMessageConverter.java
public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConverter<T> {
/**
* Set the list of {@link MediaType} objects supported by this converter.
*/
public void setSupportedMediaTypes(List<MediaType> supportedMediaTypes) {
Assert.notEmpty(supportedMediaTypes, "MediaType List must not be empty");
this.supportedMediaTypes = new ArrayList<>(supportedMediaTypes);
}
@Override
public List<MediaType> getSupportedMediaTypes() {
return Collections.unmodifiableList(this.supportedMediaTypes);
}
}
回到最上面的AllEncompassingFormHttpMessageConverter
public class AllEncompassingFormHttpMessageConverter extends FormHttpMessageConverter {
//增加转换器
public AllEncompassingFormHttpMessageConverter() {
try {
addPartConverter(new SourceHttpMessageConverter<>());
}
catch (Error err) {
// Ignore when no TransformerFactory implementation is available
}
if (jaxb2Present && !jackson2XmlPresent) {
addPartConverter(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
addPartConverter(new MappingJackson2HttpMessageConverter());
}
else if (gsonPresent) {
addPartConverter(new GsonHttpMessageConverter());
}
else if (jsonbPresent) {
addPartConverter(new JsonbHttpMessageConverter());
}
if (jackson2XmlPresent) {
addPartConverter(new MappingJackson2XmlHttpMessageConverter());
}
if (jackson2SmilePresent) {
addPartConverter(new MappingJackson2SmileHttpMessageConverter());
}
}
}
先new再增加到List
public class FormHttpMessageConverter implements HttpMessageConverter<MultiValueMap<String, ?>> {
private List<MediaType> supportedMediaTypes = new ArrayList<>();
private List<HttpMessageConverter<?>> partConverters = new ArrayList<>();
public void addPartConverter(HttpMessageConverter<?> partConverter) {
Assert.notNull(partConverter, "'partConverter' must not be null");
this.partConverters.add(partConverter);
}
}
源码分析:采用轮训的方式去逐一尝试是否可以 canWrite(POJO) ,如果返回 true,说明可以序列化该 POJO 对象,那么 Jackson 2 恰好能处理,那么Jackson 输出了JSON。
AbstractJackson2HttpMessageConverter.java的canWrite(POJO)
public abstract class AbstractJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter<Object> {
protected ObjectMapper objectMapper;
@Override
public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
if (!canWrite(mediaType)) {//我们不传任何参数进来,断点到这里
return false;
}
AtomicReference<Throwable> causeRef = new AtomicReference<>();
if (this.objectMapper.canSerialize(clazz, causeRef)) {//objectMapper序列化这个类为JSON对象(_findExplicitUntypedSerializer)
return true;
}
logWarningIfNecessary(clazz, causeRef.get());
return false;
}
}
AbstractMessageConverterMethodProcessor.java
public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
implements HandlerMethodReturnValueHandler {
protected final List<HttpMessageConverter<?>> messageConverters;
@SuppressWarnings("unchecked")
protected List<MediaType> getProducibleMediaTypes(
HttpServletRequest request, Class<?> valueClass, @Nullable Type targetType) {
Set<MediaType> mediaTypes =
(Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
if (!CollectionUtils.isEmpty(mediaTypes)) {
return new ArrayList<>(mediaTypes);
}
else if (!this.allSupportedMediaTypes.isEmpty()) {
List<MediaType> result = new ArrayList<>();
for (HttpMessageConverter<?> converter : this.messageConverters) {
if (converter instanceof GenericHttpMessageConverter && targetType != null) {//转换器要是GenericHttpMessageConverter>类型的,这个是动态的强转
if (((GenericHttpMessageConverter<?>) converter).canWrite(targetType, valueClass, null)) {//注意如果没有设置Accept类型,默认是第一个是application/json格式
result.addAll(converter.getSupportedMediaTypes());//获取支持的自描述类型
}
}
else if (converter.canWrite(valueClass, null)) {
result.addAll(converter.getSupportedMediaTypes());
}
}
return result;
}
else {
return Collections.singletonList(MediaType.ALL);
}
}
}
AbstractJackson2HttpMessageConverter.java
public abstract class AbstractJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter<Object> {
@Override
public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
if (!canWrite(mediaType)) {
return false;
}
AtomicReference<Throwable> causeRef = new AtomicReference<>();
if (this.objectMapper.canSerialize(clazz, causeRef)) {//objectMapper能否序列化这个类,json转对象(readValue),对象转Json(writeValueAsString),ObjectMapper
return true;
}
logWarningIfNecessary(clazz, causeRef.get());
return false;
}
}
这个this.messageConverters的值
this.messageConverters size = 11
0 = {ByteArrayHttpMessageConverter@6800} //ByteArray
1 = {StringHttpMessageConverter@6801} //String
2 = {StringHttpMessageConverter@6802}
3 = {ResourceHttpMessageConverter@6803} //Resource
4 = {ResourceRegionHttpMessageConverter@6804}
5 = {SourceHttpMessageConverter@6805} //Source
6 = {AllEncompassingFormHttpMessageConverter@6806} //压缩
7 = {MappingJackson2HttpMessageConverter@6746} //Jackson2Http (从这里开始加入,因为该类可以canWrite)
8 = {MappingJackson2HttpMessageConverter@6807}
9 = {MappingJackson2XmlHttpMessageConverter@6808} //Jackson2XmlHttp
10 = {MappingJackson2XmlHttpMessageConverter@6809}
对比下面增加的addDefaultHttpMessageConverters,注意顺序
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316
messageConverters.add(new ByteArrayHttpMessageConverter());//对应上面的ByteArrayHttpMessageConverter
messageConverters.add(stringHttpMessageConverter);
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new ResourceRegionHttpMessageConverter());
try {
messageConverters.add(new SourceHttpMessageConverter<>());
}
catch (Throwable ex) {
// Ignore when no TransformerFactory implementation is available...
}
messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
messageConverters.add(new AtomFeedHttpMessageConverter());
messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jackson2XmlPresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
}
else if (jaxb2Present) {
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
else if (gsonPresent) {
messageConverters.add(new GsonHttpMessageConverter());
}
else if (jsonbPresent) {
messageConverters.add(new JsonbHttpMessageConverter());
}
if (jackson2SmilePresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build()));
}
if (jackson2CborPresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.cbor();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));
}
}
}
MappingJackson2HttpMessageConverter.java
public class MappingJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
public MappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));
}
}
MappingJackson2XmlHttpMessageConverter.java
public class MappingJackson2XmlHttpMessageConverter extends AbstractJackson2HttpMessageConverter {
public MappingJackson2XmlHttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, new MediaType("application", "xml"),
new MediaType("text", "xml"),
new MediaType("application", "*+xml"));
Assert.isInstanceOf(XmlMapper.class, objectMapper, "XmlMapper required");
}
}
继续往下,发现第一个可以使用的MediaType就是application/json
public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
implements HandlerMethodReturnValueHandler {
protected final List<HttpMessageConverter<?>> messageConverters;
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
Object body;
Class<?> valueType;
Type targetType;
if (value instanceof CharSequence) {
body = value.toString();
valueType = String.class;
targetType = String.class;
}
else {
body = value;
valueType = getReturnValueType(body, returnType);
targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());
}
if (isResourceType(value, returnType)) {
outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null &&
outputMessage.getServletResponse().getStatus() == 200) {
Resource resource = (Resource) value;
try {
List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());
body = HttpRange.toResourceRegions(httpRanges, resource);
valueType = body.getClass();
targetType = RESOURCE_REGION_LIST_TYPE;
}
catch (IllegalArgumentException ex) {
outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());
outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());
}
}
}
MediaType selectedMediaType = null;
MediaType contentType = outputMessage.getHeaders().getContentType();
if (contentType != null && contentType.isConcrete()) {
if (logger.isDebugEnabled()) {
logger.debug("Found 'Content-Type:" + contentType + "' in response");
}
selectedMediaType = contentType;
}
else {
HttpServletRequest request = inputMessage.getServletRequest();
List<MediaType> acceptableTypes = getAcceptableMediaTypes(request);
List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);//这个第一个排序的是{MediaType@7002} "application/json"
if (body != null && producibleTypes.isEmpty()) {
throw new HttpMessageNotWritableException(
"No converter found for return value of type: " + valueType);
}
List<MediaType> mediaTypesToUse = new ArrayList<>();
for (MediaType requestedType : acceptableTypes) {
for (MediaType producibleType : producibleTypes) {
if (requestedType.isCompatibleWith(producibleType)) {
mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
}
}
}
if (mediaTypesToUse.isEmpty()) {
if (body != null) {
throw new HttpMediaTypeNotAcceptableException(producibleTypes);
}
if (logger.isDebugEnabled()) {
logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);
}
return;
}
MediaType.sortBySpecificityAndQuality(mediaTypesToUse);//权重排序可以使用的类型(这里进行权重排序),MimeType实现了Comparable,可进行排序
for (MediaType mediaType : mediaTypesToUse) {
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break; //选择的第一个
}
else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
break;
}
}
if (logger.isDebugEnabled()) {
logger.debug("Using '" + selectedMediaType + "', given " +
acceptableTypes + " and supported " + producibleTypes);
}
}
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter<?> converter : this.messageConverters) {
GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
(GenericHttpMessageConverter<?>) converter : null);
if (genericConverter != null ?
((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
converter.canWrite(valueType, selectedMediaType)) {
body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
inputMessage, outputMessage);
if (body != null) {
Object theBody = body;
LogFormatUtils.traceDebug(logger, traceOn ->
"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
addContentDispositionHeader(inputMessage, outputMessage);
if (genericConverter != null) {//这里判断之后写会客户端
genericConverter.write(body, targetType, selectedMediaType, outputMessage);//这里开始写到客户端
}
else {
((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Nothing to write: null body");
}
}
return;
}
}
}
if (body != null) {
throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
}
@SuppressWarnings("unchecked")
protected List<MediaType> getProducibleMediaTypes(
HttpServletRequest request, Class<?> valueClass, @Nullable Type targetType) {
Set<MediaType> mediaTypes =
(Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
if (!CollectionUtils.isEmpty(mediaTypes)) {
return new ArrayList<>(mediaTypes);
}
else if (!this.allSupportedMediaTypes.isEmpty()) {
List<MediaType> result = new ArrayList<>();
for (HttpMessageConverter<?> converter : this.messageConverters) {
if (converter instanceof GenericHttpMessageConverter && targetType != null) {//转换器要是GenericHttpMessageConverter>类型的,这个是动态的强转
if (((GenericHttpMessageConverter<?>) converter).canWrite(targetType, valueClass, null)) {//执行后回到这里,注意如果没有设置Accept类型,默认是第一个是application/json格式
result.addAll(converter.getSupportedMediaTypes());//获取支持的媒自描述类型
}
}
else if (converter.canWrite(valueClass, null)) {
result.addAll(converter.getSupportedMediaTypes());
}
}
return result;
}
else {
return Collections.singletonList(MediaType.ALL);
}
}
}
mediaTypesToUse 默认第一个就是application/json
mediaTypesToUse = {ArrayList@7070} size = 10
0 = {MediaType@7002} "application/json"
1 = {MediaType@7003} "application/*+json"
2 = {MediaType@7002} "application/json"
3 = {MediaType@7004} "application/*+json"
4 = {MediaType@7005} "application/xml"
5 = {MediaType@7006} "text/xml"
6 = {MediaType@7007} "application/*+xml"
7 = {MediaType@7018} "application/xml"
8 = {MediaType@7019} "text/xml"
9 = {MediaType@7020} "application/*+xml"
AbstractGenericHttpMessageConverter.java来写出去
public abstract class AbstractGenericHttpMessageConverter<T> extends AbstractHttpMessageConverter<T>
implements GenericHttpMessageConverter<T> {
/**
* This implementation sets the default headers by calling {@link #addDefaultHeaders},
* and then calls {@link #writeInternal}.
*/
public final void write(final T t, @Nullable final Type type, @Nullable MediaType contentType,
HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
final HttpHeaders headers = outputMessage.getHeaders();
addDefaultHeaders(headers, t, contentType);
if (outputMessage instanceof StreamingHttpOutputMessage) {
StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage;
streamingOutputMessage.setBody(outputStream -> writeInternal(t, type, new HttpOutputMessage() {
@Override
public OutputStream getBody() {
return outputStream;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
}));
}
else {
writeInternal(t, type, outputMessage);
outputMessage.getBody().flush();
}
}
}
Reading a good book, like and many noble people talk。
参考文档:
Spring Boot 2.x 启动全过程源码分析(上)入口类剖析 ↩︎
Spring Boot系列–启动方法解析监听器 ↩︎ ↩︎