对于springboot来说,还有两块是比较有意思的,第一就是发现他内置了tomcat,接下来一快就是他对springmvc进行了无缝整合
1. 内嵌tomcat首先来看下最简单的tomcat集成。
pom新建立一个servlet4.0.0 hgy embed-tomcat 1.0-SNAPSHOT org.apache.tomcat.embed tomcat-embed-core 8.5.11 org.apache.tomcat tomcat-jasper 8.5.11
package len.hgy.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class IndexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().print("this is index... tomcat");
}
}
tomcat 整合
package len.hgy;
import len.hgy.servlet.IndexServlet;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;
public class MyTomcat {
private static final int PORT = 8080;
private static final String CONTEX_PATH = "/hgy";
private static final String SERVLET_NAME = "indexServlet";
public static void main(String[] args) throws LifecycleException, InterruptedException {
// 创建tomcat服务器
Tomcat tomcatServer = new Tomcat();
// 指定端口号
tomcatServer.setPort(PORT);
// 是否设置自动部署
tomcatServer.getHost().setAutoDeploy(false);
// 创建上下文
StandardContext standardContext = new StandardContext();
standardContext.setPath(CONTEX_PATH);
// 监听上下文
standardContext.addLifecycleListener(new Tomcat.FixContextListener());
// tomcat容器添加standardContext
tomcatServer.getHost().addChild(standardContext);
// 创建Servlet
tomcatServer.addServlet(CONTEX_PATH, SERVLET_NAME, new IndexServlet());
// servleturl映射
standardContext.addServletMappingDecoded("/index", SERVLET_NAME);
tomcatServer.start();
System.out.println("tomcat服务器启动成功..");
// 异步进行接收请求
tomcatServer.getServer().await();
}
}
运行main方法,在浏览器输入:
http://localhost:8080/hgy/index
注意: 9.xx版本的并不能直接访问
2. SpringMVC 整合 新增spring依赖UserServiceorg.springframework spring-web 5.0.4.RELEASE compile org.springframework spring-webmvc 5.0.4.RELEASE compile
package len.hgy.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public String index() {
return "springboot 2.0 我正在加载UserService";
}
}
RestController
package len.hgy.controller;
import len.hgy.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
@Autowired
private UserService userService;
@RequestMapping(value = "/index", produces = "text/html;charset=UTF-8")
public String index() {
return userService.index();
}
}
DispatcherServlet配置类
虽然前面有了service,有了controller,但依然没有把这些组建交给spring,对于springmvc来说,有个DispatcherServlet,这是springmvc的前端控制器,以前是配置在web.xml中。只是现在用的是注解。
package len.hgy.conf;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("len.hgy")
public class RootConfig {
}
package len.hgy.conf;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"len.hgy.controller"})
//public class WebConfig extends WebMvcConfigurerAdapter {
public class WebConfig implements WebMvcConfigurer {
}
package len.hgy.conf;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
@Configuration
public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
// 加载根配置信息 spring核心
protected Class>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
// springmvc 加载 配置信息
protected Class>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
// springmvc 拦截url映射 拦截所有请求
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
Tomcat集成
TomcatApp
package len.hgy;
import java.io.File;
import javax.servlet.ServletException;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.StandardRoot;
public class TomcatApp {
public static void main(String[] args) throws ServletException, LifecycleException {
start();
}
public static void start() throws ServletException, LifecycleException {
// 创建Tomcat容器
Tomcat tomcatServer = new Tomcat();
// 端口号设置
tomcatServer.setPort(9090);
// 读取项目路径 加载静态资源
StandardContext ctx = (StandardContext) tomcatServer.addWebapp("/", new File("src/main").getAbsolutePath());
// 禁止重新载入
ctx.setReloadable(false);
// class文件读取地址
File additionWebInfClasses = new File("target/classes");
// 创建WebRoot
WebResourceRoot resources = new StandardRoot(ctx);
// tomcat内部读取Class执行
resources.addPreResources(
new DirResourceSet(resources, "/WEB-INF/classes", additionWebInfClasses.getAbsolutePath(), "/"));
tomcatServer.start();
// 异步等待请求执行
tomcatServer.getServer().await();
}
}
启动,在地址栏输入:
http://localhost:9090/index
JSP支持要支持JSP,回忆学习springmvc中的内容,需要用到一个试图解析器
修改WebConfig
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"len.hgy.controller"})
//public class WebConfig extends WebMvcConfigurerAdapter {
public class WebConfig implements WebMvcConfigurer {
// 创建SpringMVC视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
// 可以在JSP页面中通过${}访问beans
viewResolver.setExposeContextBeansAsAttributes(true);
registry.viewResolver(viewResolver);
}
}
新增controller
@Controller
public class UserController {
@RequestMapping("/pageIndex")
public String pageIndex() {
return "pageIndex";
}
}
增加JSP
在resources里面新增WEB-INFviewspageIndex.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
jsp page
这是个jsp页面
重启tomcat ,访问 http://localhost:9090/pageIndex
3. SpringBootTomcat 加载流程 tomcat如何启动的?org.springframework.boot.autoconfigure.EnableAutoConfiguration= ... org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration, ...
ServletWebServerFactoryAutoConfiguration 这类里面有个TomcatServletWebServerFactoryCustomizer这个类实现了WebServerFactoryCustomizer
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
EmbeddedTomcat->TomcatServletWebServerFactory->TomcatServletWebServerFactory.getWebServer()->getTomcatWebServer->TomcatWebServer->启动tomcat
// Start the server to trigger initialization listeners
this.tomcat.start();
在注入bean时候已经在构造器里面启动了tomcat
getWebServer谁调用的?SpringApplication.run(App.class, args);
org.springframework.boot.SpringApplication#refreshContext
org.springframework.context.support.AbstractApplicationContext#refresh (Spring启动的核心方法)
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#createWebServer
org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getWebServer
大致分析:
更具classpath中的class分析出当前的项目类型是REACTIVE, SERVELET, NONE, 如果是SERVLET类型创建ServletWebServerApplicationContext的Context, 在AbstractApplicationContext的onRefresh()的钩子方法调用ServletWebServerApplicationContext的onRefresh()方法调用createWebServer(),最终调用如下代码和Tomcat挂钩
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
}
以上是SpringBoot在onRefresh()中启动Tomcat的逻辑, 其实还是在Spring的refresh()流程中
Tomcat如何初始化Spring呢?只需要在refresh()方法打一个断点就知道了
其中有好几个异步追踪, 说明Tomcat初始化Spring使用的是异步线程方式
main线程
tomcatServer.start();
server.start();
startInternal(); 提交异步任务
异步任务线程1
异步任务线程2
listener.contextInitialized(tldEvent);
public void contextInitialized(ServletContextEvent event) {
this.initWebApplicationContext(event.getServletContext());
}
configureAndRefreshWebApplicationContext的实例是AnnotationConfigWebApplicationContext
而AnnotationConfigWebApplicationContext的继承结构是
所以在调用refresh()方法就会触发spring初始化的核心逻辑
而此时的onRefresh()钩子方法不会触发再次Tomcat启动, 所以不会出现Tomcat重复启动
@Override
protected void onRefresh() {
this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}
4. SpringBoot 启动流程分析
准备工作
ApplicationContextInitializer Context初始化后调用的类
SpringApplicationRunListener SpringBoot运行监听的类
ApplicationRunner/CommandLineRunner 两个几乎可以等价,用于启动后做客户自定义的操作
MyApplicationRunner
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("MyApplicationRunner.run()执行了");
}
}
MyCommandLineRunner
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("MyCommandLineRunner.run()执行了" + Arrays.asList(args));
}
}
MyApplicationContextInitializer
public class MyApplicationContextInitializer
implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("MyApplicationContextInitializer.initialize()执行了" + applicationContext);
}
}
MySpringApplicationRunListener
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
//必须有的构造器
public MySpringApplicationRunListener(SpringApplication application, String[] args) {
}
@Override
public void starting() {
System.out.println("MySpringApplicationRunListener.starting()执行了");
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
System.out.println("MySpringApplicationRunListener.environmentPrepared()执行了");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("MySpringApplicationRunListener.contextPrepared()执行了");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("MySpringApplicationRunListener.contextLoaded()执行了");
}
@Override
public void started(ConfigurableApplicationContext context) {
System.out.println("MySpringApplicationRunListener.started()执行了");
}
@Override
public void running(ConfigurableApplicationContext context) {
System.out.println("MySpringApplicationRunListener.running()执行了");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("MySpringApplicationRunListener.failed()执行了");
}
}
在resources/meta-INF/spring.factories增加
org.springframework.context.ApplicationContextInitializer=len.hgy.listener.MyApplicationContextInitializer org.springframework.boot.SpringApplicationRunListener=len.hgy.listener.MySpringApplicationRunListener创建SpringApplication
SpringApplication源码
public static ConfigurableApplicationContext run(Class> primarySource,
String... args) {
return run(new Class>[] { primarySource }, args);
}
其实SpringBoot启动就着两个步骤,先创建ConfigurableApplicationContext ,然后再调用Run方法。
ConfigurableApplicationContext 是其他方式接入Spring的入口上下文
SpringApplication构造方法源码
public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//保存主类
this.primarySources = new linkedHashSet<>(Arrays.asList(primarySources));
//判断当前是什么类型项目, Tomcat启动Spring不需要判断,因为使用Tomcat就说明是SERVLET类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从类路径下找到meta-INF/spring.factories配置的所有 ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//从类路径下找到meta-INF/spring.factories配置的所有ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
Run方法
核心方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//从类路径下meta‐INF/spring.factories,取得 SpringApplicationRunListeners;
SpringApplicationRunListeners listeners = getRunListeners(args);
//回调所有的获取SpringApplicationRunListener.starting()方法
listeners.starting();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
//创回调SpringApplicationRunListener.environmentPrepared();
//表示环境准备完成
//打印 Banner
Banner printedBanner = printBanner(environment);
//根据环境创建context
context = createApplicationContext();
//错误的异常报表
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备上下文环境;
//将environment保存到ioc中;
//applyInitializers()调用所有的ApplicationContextInitializer的initialize方法
//调用所有的SpringApplicationRunListener的contextPrepared();
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//SpringApplicationRunListener的contextLoaded
//刷新容器
//扫描,创建,加载所有组件;
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//所有的SpringApplicationRunListener回调started方法
listeners.started(context);
//获取所有的ApplicationRunner和CommandLineRunner进行调用
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//所有的SpringApplicationRunListener的running();
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
注意
ApplicationContextInitializer是在构造方法中从spring.factories中获取初始化的
SpringApplicationRunListener是在run中获取的
callRunners(context, applicationArguments); // 会调用所有的ApplicationRunner和CommandLineRunner
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List
spi的bean不需要加注解就可以导入到Spring中, Runner需要加注解才能导入
总结:springboot的启动核心步骤就是调用refresh()方法,启动spring核心流程, 调用onRefresh()方法, new Tomcat(),并设置tomcat项目路径,端口等(就是创建一个类似web.xml的对象)
另外springboot还有一个核心功能是自动配置, 接下来看自动配置
1、SPI
SPI 在 springboot 中是去读取 meta-INF/spring.factories 目录的配置文件内 容,把配置文件中的类加载到 spring 容器中。这样如果你想把一个类加载到 spring 容器中,也可以采用这种方式来做。把类配置到 spring.factories 配置 文件中即可。
如果你想把一个类加载到 spring 容器中管理有几种方式:
1、通过 xml 的 bean 标签
2、通过加@Component 注解被@ComponentScan 扫描
3、通过在 spring.factories 配置该类
前两者是加载本工程的 bean,扫描本工程的 bean,第三点可以加载第三方定义 的 jar 包中的 bean,毕竟第三方 jar 包的包名跟本工程包名可能不一样,所以 前两个方式扫描不到。
2、创建 springboot 的上下文对象
在这个上下文对象构造函数中把 ConfigurationClassPostProcessor 变成 beanDefinition 对象(核心的ConfigurationClassPostProcessor 是在这个地方编程了BeanDefinition的)
public class AnnotationConfigServletWebServerApplicationContext
extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
...
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
...
}
this.reader = new AnnotatedBeanDefinitionReader(this);
// 注册 ConfigurationClassPostProcessor的BeanDefinition
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
3、容器的启动
其实很简单就是调用了上下文对象的 refresh 核心方法:
// 核心方法, 启动Spring容器
refreshContext(context);
// 进入AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// 创建BeanFactory和xml的标签解析哦
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); // 设置一些属性, 不重要
try {
// 允许在上下文子类中对bean工厂进行后处理, 主要是注册WebApplication的Scopes和Environment的Beans到BeanFactory中, 所以是到beanFactory的后处理
//WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
//WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
postProcessBeanFactory(beanFactory);
* private final List beanFactoryPostProcessors = new ArrayList<>();
* SpringBoot中在applyInitializers(context);里面添加这个容器
* 这些bean不在核心容器里面, 是在一个单独的beanFactoryPostProcessors中
* 通过getBean实例化,让后调用后置处理器
* currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
* */
invokeBeanFactoryPostProcessors(beanFactory); // 是BeanDefinitionRegistry和BeanFactory的后置处理器调用
registerBeanPostProcessors(beanFactory); // 是Bean的后置处理器调用
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh(); // new Tomcat(), 并启动
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
4、内置 tomcat 的启动和部署
Tomcat 的启动在 onRefresh()中:
// org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat(); // host
File baseDir = (this.baseDirectory != null) ? this.baseDirectory
: createTempDir("tomcat");
tomcat.setbaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol); // connector
tomcat.getService().addConnector(connector); // set service
customizeConnector(connector);
tomcat.setConnector(connector); // set connector
tomcat.getHost().setAutoDeploy(false); // 设置非自动部署
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}
SpringBoot启动核心就做了两件是
启动Spring的refresh()方法(refresh())
AbstractApplicationContext启动核心流程中回调ServletWebServerApplicationContext.onRefresh()的钩子方法(onRefresh())
5. SpringBoot的自动配置 为什么要有 springboot 自动配置功能?在 springboot 项目中,我们可以在业务代码里面用事务注解,用缓存注解,用 mvn 相关的功能等等,但是我们并没有在 springboot 项目把这些功能开启添加 进来,那么为什么我们可以在业务代码中使用这些功能呢?也就是说这些功能如 何跑到 springboot 项目中来的呢?这就是 springboot 的自动配置功能
自动配置功能开启
@SpringBootConfiguration
@EnableAutoConfiguration // SpringBoot自动配置注解
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@AutoConfigurationPackage
@import(AutoConfigurationimportSelector.class) // 使用import导入
public @interface EnableAutoConfiguration {
那这个AutoConfigurationimportSelector如何被调用的?
在refresh()的核心流程中有两个非常重要的后置处理方法
invokeBeanFactoryPostProcessors(beanFactory); // BeanDefinitionRegistry和BeanFactory的后置处理器
// 这两个是对beanFactory的修改(当然, 主要是修改BeanDefinition)
// 继承关系 public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); // BeaDefinitionRegistry
// BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(registry);
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); // BeanFactory
// BeanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
// BeanDefinitionRegistryPostProcessor调用后将对象添加到BeanFactoryPostProcessor容器中
// 所以BeanDefinitionRegistryPostProcessor容器是BeanFactoryPostProcessor容器的一个自己
// 所有的BeanDefinitionRegistryPostProcessor对象会调用postProcessBeanDefinitionRegistry和postProcessBeanFactory两个方法
registerBeanPostProcessors(beanFactory); // BeanPostProcessor接口的调用, 即bean的后置处理器调用
public interface BeanPostProcessor { // 接口可以看出, bean的后置处理器是对Bean的修改
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean; // 默认不修改返回原始bean
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean; // 默认不修改返回原始bean
}
}
@Configuration,@import,@Bean,@importResource,@ComponentScan等注解是在ConfigurationClassPostProcessor中完成的
ConfigurationClassPostProcessor的类结构
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
理所当然Registry的postProcessBeanDefinitionRegistry后置处理器就是处理这些注解的入口
@Override // 不用忘记了, 这个是refresh核心流程调用过来的invokeBeanFactoryPostProcessor()
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry); // 处理配置beanDefinition, 处理注解的核心逻辑
}
this.deferredimportSelectorHandler.process(); // deferredimportSelector的处理器
// ConfigurationClassParser.DeferredimportSelectorHandler#process
public void process() {
List deferredimports = this.deferredimportSelectors;
this.deferredimportSelectors = null;
try {
if (deferredimports != null) {
DeferredimportSelectorGroupingHandler handler = new DeferredimportSelectorGroupingHandler();
deferredimports.sort(DEFERRED_import_COMPARATOR);
deferredimports.forEach(handler::register);
handler.processGroupimports(); // 处理 group imports逻辑
}
} finally {
this.deferredimportSelectors = new ArrayList<>();
}
}
// ConfigurationClassParser.DeferredimportSelectorGrouping#getimports
public Iterable getimports() {
for (DeferredimportSelectorHolder deferredimport : this.deferredimports) {
this.group.process(deferredimport.getConfigurationClass().getmetadata(),
deferredimport.getimportSelector()); // process调用importSelector的接口方法
}
return this.group.selectimports();
}
AutoConfigurationimportSelector的类继承结构如下
public class AutoConfigurationimportSelector // 是DeferredimportSelector的类
implements DeferredimportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {
getimports()->this.group.process()->AutoConfigurationimportSelector.AutoConfigurationGroup#process()
->AutoConfigurationimportSelector#getAutoConfigurationEntry()
->AutoConfigurationimportSelector#getCandidateConfigurations()
-> SpringFactoriesLoader.loadFactoryNames() // 此处就是SpringBoot通过SPI获取spring.Factories中bean实现,然后导入里面的类的
public static ListloadFactoryNames(Class> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); }
然后就是Spring的import注解的处理逻辑
AutoConfigurationimportSelector实现了 DeferredimportSelector 接口。 这个类的核心功能是通过 SPI 机制收集 EnableAutoConfiguration 为 key 的所有 类,然后通过 ConfigurationClassPostProcessor 这个类调用到该类中的方法, 把收集到的类变成 beanDefinition 对象最终实例化加入到 spring 容器。
# Auto Configure, 一个实现代表导入一个功能 org.springframework.boot.autoconfigure.EnableAutoConfiguration= org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration, org.springframework.boot.autoconfigure.aop.AopAutoConfiguration, org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration, org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration, org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, ...
AutoConfigurationimportSelector 类中两个方法会被 ConfigurationClassPostProcessor 调到:
org.springframework.boot.autoconfigure.AutoConfigurationimportSelector.AutoConfigurationGroup#process
org.springframework.boot.autoconfigure.AutoConfigurationimportSelector#selectimports
在这两个方法中完成了 SPI 类的收集。
ConfigurationClassPostProcessor 类只是把收集到的类变成 beanDefinition 并加入到 spring 容器。
ConfigurationClassPostProcessor 类调用的地方。
private void processimports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection importCandidates, boolean checkForCircularimports) {
...
if (candidate.isAssignable(importSelector.class)) {
// Candidate class is an importSelector -> delegate to it to determine imports
Class> candidateClass = candidate.loadClass();
// 需要实例化这个候选的bean
importSelector selector = BeanUtils.instantiateClass(candidateClass, importSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredimportSelector) { // 看看是不是一个Defer selector(延迟被导入的)
this.deferredimportSelectorHandler.handle( // 处理加入
configClass, (DeferredimportSelector) selector);
} else {
String[] importClassNames = selector.selectimports(currentSourceClass.getmetadata());
Collection importSourceClasses = asSourceClasses(importClassNames);
processimports(configClass, currentSourceClass, importSourceClasses, false);
}
}
...
}
public void handle(ConfigurationClass configClass, DeferredimportSelector importSelector) {
DeferredimportSelectorHolder holder = new DeferredimportSelectorHolder(
configClass, importSelector);
if (this.deferredimportSelectors == null) {
DeferredimportSelectorGroupingHandler handler = new DeferredimportSelectorGroupingHandler();
handler.register(holder);
handler.processGroupimports(); // 调用处理
}
else {
this.deferredimportSelectors.add(holder);
}
}
public void processGroupimports() {
for (DeferredimportSelectorGrouping grouping : this.groupings.values()) {
grouping.getimports().forEach(entry -> { // here
ConfigurationClass configurationClass = this.configurationClasses.get(
entry.getmetadata());
try {
processimports(configurationClass, asSourceClass(configurationClass),
asSourceClasses(entry.getimportClassName()), false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configurationClass.getmetadata().getClassName() + "]", ex);
}
});
}
}
public Iterable getimports() {
for (DeferredimportSelectorHolder deferredimport : this.deferredimports) {
// 调用 process
this.group.process(deferredimport.getConfigurationClass().getmetadata(),
deferredimport.getimportSelector());
}
return this.group.selectimports(); // selectimports
}
这就是这两个方法的调用地方。
上述就是 EnableAutoConfiguration 为 key 自动配置类的收集过程。有自动配置类的收集并加入到 spring 容器,前面提到的 aop,事务,缓存,mvc 功能就已经导入到 springboot 工程了。
6. AOP 功能的自动配置类# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration= org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration, org.springframework.boot.autoconfigure.aop.AopAutoConfiguration, org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
AopAutoConfiguration
这个就是 AOP 功能的自动配置类,如果我们要开启 aop 功能,必须要在 xml 里面加配置或者用注解的方式手动开启 aop 功能、注解方式开启 aop
功能如图:
手动开启 aop 功能的这个注解其实就是往 spring 容器里面加入了 一个支持 aop 功能的入口类。
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,
AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}
默认是开启 aop 自动配置功能的,默认是开启了 cglib 的动态代理功能的,并且也加上了EnableAspectJAutoProxy(proxyTargetClass = false) 注解了,加上这个注解就会开启 aop 功能。
EnableAspectJAutoProxy这个注解可以作用在内部类, 并且在SpringBoot的自动配置类中经常出现内部类, 并且这两个方法都是标记作用,没有任何实现逻辑
EnableAspectJAutoProxy说明
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
Configuration说明
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
boolean proxyBeanMethods() default true; // 代理@Bean的方法, 默认代理且代理都是通过CGLIB代理实现, 这里没有使用JDK的选项, 这里和EnableAspectJAutoProxy#proxyTargetClass的相同,true表示使用cglib, 只不过这里的false不使用代理, 默认比是true不是false
}
7. Condition 功能的实现
Condition 功能的使用很简单 使用的需求是:有的时候我们需要当某一个条件满足的时候才把一些类实例化并 加入到 spring 容器中。
@ConditionalOnBean: 当 spring 容器中存在 jack 这个 bean 时,才调用该方法
@Bean
@ConditionalOnBean(name = "order")
public User CglibAutoProxyConfiguration {
return new User();
}
其他注解类似
@ConditionalOnClass
@ConditionalOnMissingBean
@ConditionalOnMissingClass
@ConditionalOnexpression( " ${spring.datasource.max-idle} == 10")
@ConditionalOnProperty(perfix = “spring.redis”, name = “host”, havingValue = “192.168.10.10”)
自定义 conditionpublic class CustomCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypemetadata metadata) {
System.out.println("=====CustomCondition.matches======");
String property = context.getEnvironment().getProperty("spring.redis.jedis.pool.max-active");
return !"8".equals(property);
}
}
当自定义 CustomCondition 中的 matches 方法返回 true 时才会调用到该方法。 @Conditional 注解作用在类上面也是一样的使用方式
@Component
@Conditional(value = CustomCondition.class)
public class CustomConditionBean {
}
Condition 的原理和源码
从 condition 的使用需求我们知道,这个是单条件满足的时候才实例化 bean 和 加入到 spring 容器,而在 spring 中一个类的实例化必须要变成 beanDefinition 对象。而 ConfigurationClassPostProcessor 是所有 beanDefinition 对象的集散地,所有的 beanDefinition 都会在这个类里面处理。那么我们要完成 Condition 功能也必定在这个类里面。
ConfigurationClassParser类中的 shouldSkip 方法就是做 bean 过滤 的。
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionevaluator.shouldSkip(configClass.getmetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
...
}
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
// matches方法,是核心方法
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
SpringBootCondition#matches(ConditionContext, AnnotatedTypemetadata)
public final boolean matches(ConditionContext context, AnnotatedTypemetadata metadata) {
String classOrMethodName = getClassOrMethodName(metadata);
try {
// 模板方法,不同注解调用实现不一样
ConditionOutcome outcome = getMatchOutcome(context, metadata);
logOutcome(classOrMethodName, outcome);
recordevaluation(context, classOrMethodName, outcome);
return outcome.isMatch();
}
catch (NoClassDefFoundError ex) {
throw new IllegalStateException("...", ex);
}
catch (RuntimeException ex) {
throw new IllegalStateException("Error processing condition on " + getName(metadata), ex);
}
}
这里看两个注解的实现
org.springframework.boot.autoconfigure.condition.ConditionalOnBean对应的注解实现是: org.springframework.boot.autoconfigure.condition.OnBeanCondition
Bean 存在时才掉用方法,这个其实很好理解,判断 bean 是否存在其实就只要从 BeanFactory 中找就行了,源码里面就是从 BeanFactory 中找。
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypemetadata metadata) {
ConditionMessage matchMessage = ConditionMessage.empty();
MergedAnnotations annotations = metadata.getAnnotations();
if (annotations.isPresent(ConditionalOnBean.class)) {
Spec spec = new Spec<>(context, metadata, annotations, ConditionalOnBean.class);
MatchResult matchResult = getMatchingBeans(context, spec); // 核心逻辑
if (!matchResult.isAllMatched()) {
String reason = createOnBeanNoMatchReason(matchResult);
return ConditionOutcome.noMatch(spec.message().because(reason));
}
matchMessage = spec.message(matchMessage).found("bean", "beans").items(Style.QUOTE,
matchResult.getNamesOfAllMatches());
}
...
return ConditionOutcome.match(matchMessage);
}
protected final MatchResult getMatchingBeans(ConditionContext context, Spec> spec) {
...
MatchResult result = new MatchResult();
Set beansIgnoredByType = getNamesOfBeansIgnoredByType(classLoader, beanFactory, considerHierarchy,spec.getIgnoredTypes(), parameterizedContainers);
for (String type : spec.getTypes()) {
// 更具注解类型从容器中获取bean
Collection typeMatches = getBeanNamesForType(classLoader, considerHierarchy, beanFactory, type, parameterizedContainers);
typeMatches.removeAll(beansIgnoredByType);
if (typeMatches.isEmpty()) {
result.recordUnmatchedType(type);
}
else {
result.recordMatchedType(type, typeMatches);
}
}
...
return result;
}
从 BeanFactory 中获取对应的实例,如果有则匹配。
org.springframework.boot.autoconfigure.condition.ConditionalOnClass对应的注解实现是: org.springframework.boot.autoconfigure.condition.OnClassCondition
当工程上下文中存在该类时才调用方法 实现原理,就是通过反射的方式,如果反射有异常则返回 false,如果反射没异 常返回 true
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypemetadata metadata) {
ClassLoader classLoader = context.getClassLoader();
ConditionMessage matchMessage = ConditionMessage.empty();
List onClasses = getCandidates(metadata, ConditionalOnClass.class);
if (onClasses != null) {
// 核心逻辑
List missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);
if (!missing.isEmpty()) {
return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
.didNotFind("required class", "required classes").items(Style.QUOTE, missing));
}
matchMessage = matchMessage.andCondition(ConditionalOnClass.class)
.found("required class", "required classes")
.items(Style.QUOTE, filter(onClasses, ClassNameFilter.PRESENT, classLoader));
}
List onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);
if (onMissingClasses != null) {
List present = filter(onMissingClasses, ClassNameFilter.PRESENT, classLoader);
if (!present.isEmpty()) {
return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnMissingClass.class)
.found("unwanted class", "unwanted classes").items(Style.QUOTE, present));
}
matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class)
.didNotFind("unwanted class", "unwanted classes")
.items(Style.QUOTE, filter(onMissingClasses, ClassNameFilter.MISSING, classLoader));
}
return ConditionOutcome.match(matchMessage);
}
protected final Listfilter(Collection classNames, ClassNameFilter classNameFilter, ClassLoader classLoader) { if (CollectionUtils.isEmpty(classNames)) { return Collections.emptyList(); } List matches = new ArrayList<>(classNames.size()); for (String candidate : classNames) { if (classNameFilter.matches(candidate, classLoader)) { // 一个枚举方法,看入参的实现 matches.add(candidate); } } return matches; }
MISSING {
@Override
public boolean matches(String className, ClassLoader classLoader) {
return !isPresent(className, classLoader);
}
};
static boolean isPresent(String className, ClassLoader classLoader) {
if (classLoader == null) {
classLoader = ClassUtils.getDefaultClassLoader();
}
try {
resolve(className, classLoader); // 看是否有异常
return true;
}
catch (Throwable ex) {
return false;
}
}
8. Redis 自动配置
自动配置类
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,
为什么可以在程序里面直接依赖注入 RedisTemplate,在自动配置类创建了该实
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class) // 更具class决定是否引入该功能
@EnableConfigurationProperties(RedisProperties.class) // 开启配置属性的java bean
@import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) // 导入功能相关类
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate") // 没有bean时候才注入
public RedisTemplate
9. 数据源自动配置
自动配置类
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
// 导入公共类
@import({ DataSourcePoolmetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@Conditional(EmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@import(EmbeddedDataSourceConfiguration.class) // 导入需要的类
protected static class EmbeddedDatabaseConfiguration {
}
@Configuration(proxyBeanMethods = false)
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration {
}
static class PooledDataSourceCondition extends AnyNestedCondition {
PooledDataSourceCondition() {
super(ConfigurationPhase.PARSE_CONFIGURATION);
}
@ConditionalOnProperty(prefix = "spring.datasource", name = "type")
static class ExplicitType {
}
@Conditional(PooledDataSourceAvailableCondition.class)
static class PooledDataSourceAvailable {
}
}
static class PooledDataSourceAvailableCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypemetadata metadata) {
ConditionMessage.Builder message = ConditionMessage.forCondition("PooledDataSource");
if (DataSourceBuilder.findType(context.getClassLoader()) != null) {
return ConditionOutcome.match(message.foundExactly("supported DataSource"));
}
return ConditionOutcome.noMatch(message.didNotFind("supported DataSource").atAll());
}
}
static class EmbeddedDatabaseCondition extends SpringBootCondition {
private final SpringBootCondition pooledCondition = new PooledDataSourceCondition();
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypemetadata metadata) {
ConditionMessage.Builder message = ConditionMessage.forCondition("EmbeddedDataSource");
if (anyMatches(context, metadata, this.pooledCondition)) {
return ConditionOutcome.noMatch(message.foundExactly("supported pooled data source"));
}
EmbeddedDatabaseType type = EmbeddedDatabaseConnection.get(context.getClassLoader()).getType();
if (type == null) {
return ConditionOutcome.noMatch(message.didNotFind("embedded database").atAll());
}
return ConditionOutcome.match(message.found("embedded database").items(type));
}
}
}
默认是有 Hikari 数据源对象的。
// org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration.Hikari
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",
matchIfMissing = true)
static class Hikari {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
}
10. JdbcTemplate 自动配置
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
@import({ JdbcTemplateConfiguration.class, NamedParameterJdbcTemplateConfiguration.class })
public class JdbcTemplateAutoConfiguration {
}
JdbcTemplateConfiguration配置JdbcTemplate的bean
@Configuration(proxyBeanMethods = false) // false, 说明,每次调用都会原始方法,即不代理原始方法
@ConditionalOnMissingBean(JdbcOperations.class)
class JdbcTemplateConfiguration {
@Bean
@Primary
JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
JdbcProperties.Template template = properties.getTemplate();
jdbcTemplate.setFetchSize(template.getFetchSize());
jdbcTemplate.setMaxRows(template.getMaxRows());
if (template.getQueryTimeout() != null) {
jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
}
return jdbcTemplate;
}
}
11. 事务管理器自动配置
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class })
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceTransactionManagerAutoConfiguration {
@Configuration(proxyBeanMethods = false) // 不使用代理(CGLIB代理:true), 即每次都调用原始的@Bean方法
@ConditionalOnSingleCandidate(DataSource.class)
static class DataSourceTransactionManagerConfiguration {
@Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class)
DataSourceTransactionManager transactionManager(DataSource dataSource,
ObjectProvider transactionManagerCustomizers) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
return transactionManager;
}
}
}
12. 事务自动配置
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,
编程式事务
@Configuration(proxyBeanMethods = false)
@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
public static class TransactionTemplateConfiguration {
@Bean
@ConditionalOnMissingBean(TransactionOperations.class)
public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
return new TransactionTemplate(transactionManager);
}
}
事务功能导入注解
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(TransactionManager.class)
@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
public static class EnableTransactionManagementConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableTransactionManagement(proxyTargetClass = false) // 开启事务管理器代理
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableTransactionManagement(proxyTargetClass = true) // 开启事务管理器代理
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}
13. DispatcherServlet 自动配置
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,
DispatcherServlet
@Configuration(proxyBeanMethods = false)
@Conditional(DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class })
protected static class DispatcherServletConfiguration {
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet(HttpProperties httpProperties, WebMvcProperties webMvcProperties) {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
dispatcherServlet.setEnableLoggingRequestDetails(httpProperties.isLogRequestDetails());
return dispatcherServlet;
}
@Bean
@ConditionalOnBean(MultipartResolver.class)
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
public MultipartResolver multipartResolver(MultipartResolver resolver) {
// Detect if the user has created a MultipartResolver but named it incorrectly
return resolver;
}
}
DispatcherServletRegistrationBean
@Configuration(proxyBeanMethods = false)
@Conditional(DispatcherServletRegistrationCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
@import(DispatcherServletConfiguration.class)
protected static class DispatcherServletRegistrationConfiguration {
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
WebMvcProperties webMvcProperties, ObjectProvider multipartConfig) {
DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
webMvcProperties.getServlet().getPath());
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
multipartConfig.ifAvailable(registration::setMultipartConfig);
return registration;
}
}
14. MVC 自动配置
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,
其实 mvc 的自动配置就是把一些支持 mvc 功能的类创建出来 比如:handlerMapping,HandlerAdapter,ViewResolver 等等实例
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter( // 映射处理适配器
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager,
conversionService, validator);
adapter.setIgnoreDefaultModelOnRedirect(
this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
return adapter;
}
@Override
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() { // 被调用的方法
if (this.mvcRegistrations != null && this.mvcRegistrations.getRequestMappingHandlerAdapter() != null) {
return this.mvcRegistrations.getRequestMappingHandlerAdapter();
}
return super.createRequestMappingHandlerAdapter();
}
@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping( // 映射处理器
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
// Must be @Primary for MvcUriComponentsBuilder to work
return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
resourceUrlProvider);
}
@Bean // 欢迎页面映射
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
return welcomePageHandlerMapping;
}
private Optional getWelcomePage() { // 获取欢迎页面
String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}
private Resource getIndexHtml(String location) { // 获取默认的索引页面, index.html
return this.resourceLoader.getResource(location + "index.html");
}
@Bean
@Override
public FormattingConversionService mvcConversionService() {
WebConversionService conversionService = new WebConversionService(this.mvcProperties.getDateFormat());
addFormatters(conversionService);
return conversionService;
}
@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() { // 内部视图解析器
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix(this.mvcProperties.getView().getPrefix());
resolver.setSuffix(this.mvcProperties.getView().getSuffix());
return resolver;
}



