8.嵌入式Servlet容器
(1).切换嵌入式Servlet容器
- 默认支持的
webServer
Tomcat
,Jetty
, orUndertow
ServletWebServerApplicationContext
容器启动寻找ServletWebServerFactory
并引导创建服务器
ServletWebServerApplicationContext: 174行 private void createWebServer() { WebServer webServer = this.webServer; // 1.获取servletContext容器 ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null) { // 2.创建服务器容器 StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create"); ServletWebServerFactory factory = getWebServerFactory(); createWebServer.tag("factory", factory.getClass().toString()); // ⭐⭐3.获取Tomcate容器 this.webServer = factory.getWebServer(getSelfInitializer()); createWebServer.end(); getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer)); getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer)); } else if (servletContext != null) { try { getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } initPropertySources(); }
- 切换服务器
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency>
- 原理
- SpringBoot应用启动发现当前是Web应用。web场景包-导入tomcat
- web应用会创建一个web版的ioc容器 ServletWebServerApplicationContext
- ServletWebServerApplicationContext 启动的时候
寻找 ServletWebServerFactory
(Servlet 的web服务器工厂—> Servlet 的web服务器) - SpringBoot底层默认有3个的WebServer工厂;
TomcatServletWebServerFactory
,JettyServletWebServerFactory
, orUndertowServletWebServerFactory
- 底层直接会有一个自动配置类 。
ServletWebServerFactoryAutoConfiguration类
ServletWebServerFactoryAutoConfiguration
导入了ServletWebServerFactoryConfiguration
(配置类)ServletWebServerFactoryConfiguration 配置类
根据动态判断系统中到底导入了那个Web服务器的包。(默认是web-starter导入tomcat包
),容器中就有 TomcatServletWebServerFactoryTomcatServletWebServerFactory 创建出Tomcat服务器并启动
;TomcatWebServer 的构造器拥有初始化方法initialize—this.tomcat.start();- 内嵌服务器,就是手动把启动服务器的代码调用(tomcat核心jar包存在)
(2).定制Servlet容器
- 实现
WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>
- 把配置文件的值和
ServletWebServerFactory
进行绑定
- 修改配置文件 server.xxx (
第一种方式
) - 直接自定义 ConfigurableServletWebServerFactory (
第二种
)
因为我们项目已启动ServletWebServerFactory就会引导创建服务器,所以我们直接引入子类集大成者即可。
import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; import org.springframework.stereotype.Component; @Component public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> { @Override public void customize(ConfigurableServletWebServerFactory server) { server.setPort(9000); } }
9.定制化原理
(1).定制化的常见方式
- 修改配置文件;
- xxxxxCustomizer;
- 编写自定义的配置类 xxxConfiguration;+ @Bean替换、增加容器中默认组件;视图解析器
- Web应用 编写一个配置类实现 WebMvcConfigurer 即可定制化web功能;+ @Bean给容器中再扩展一些组件
@Configuration public class AdminWebConfig implements WebMvcConfigurer
@EnableWebMvc + WebMvcConfigurer + @Configuration
—— @Bean 可以全面接管SpringMVC,所有规则全部自己重新配置; 实现定制和扩展功能
- 原理
- 1、
WebMvcAutoConfiguration
默认的SpringMVC的自动配置功能类。静态资源、欢迎页… - 2、一旦使用
@EnableWebMvc
、。会 @Import(DelegatingWebMvcConfiguration.class) - 3、DelegatingWebMvcConfiguration 的 作用,
只保证SpringMVC最基本的使用
- 把所有系统中的 WebMvcConfigurer 拿过来。
所有功能的定制都是这些 WebMvcConfigurer 合起来一起生效 (也就是说手动生效了)
- 自动配置了一些非常底层的组件。RequestMappingHandlerMapping、这些组件依赖的组件都是从容器中获取
- public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
- 4、WebMvcAutoConfiguration 里面的配置要能生效 必须
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
- 5、@EnableWebMvc 导致了
WebMvcAutoConfiguration
没有生效。
● … …
(2).原理分析套路
场景starter - xxxxAutoConfiguration - 导入xxx组件 - 绑定xxxProperties – 绑定配置文件项
3.数据访问
1.SQL
(1).数据源的自动配置-HikariDataSource
(1.1) 、导入JDBC场景
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency>
数据库驱动?
为什么导入JDBC场景,官方不导入驱动?
官方不知道我们接下要操作什么数据库(MySQL.Orangle)。
数据库版本和驱动版本对应
SpringBoot默认版本:<mysql.version>8.0.22</mysql.version> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <!-- <version>5.1.49</version>--> </dependency> 想要修改版本 1、直接依赖引入具体版本(maven的就近依赖原则) 2、重新声明版本(maven的属性的就近优先原则) <properties> <java.version>1.8</java.version> <mysql.version>5.1.6</mysql.version> </properties>
(1.2) 、分析自动配置JDBC引入了啥
自动配置的类
- DataSourceAutoConfiguration :
数据源的自动配置
- 修改数据源相关的配置:
spring.datasource
- 数据库连接池的配置,是自己容器中没有
DataSource
才自动配置的 - 底层配置好的连接池是:HikariDataSource
@Configuration(proxyBeanMethods = false) @Conditional(PooledDataSourceCondition.class) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class, DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class }) protected static class PooledDataSourceConfiguration
- DataSourceTransactionManagerAutoConfiguration:
事务管理器的自动配置
- JdbcTemplateAutoConfiguration:
JdbcTemplate的自动配置,可以来对数据库进行crud
- 可以修改这个配置项@ConfigurationProperties(prefix = “spring.jdbc”) 来修改JdbcTemplate
- @Bean@Primary JdbcTemplate;
容器中有这个组件(所以我们自己使用即可)
- JndiDataSourceAutoConfiguration:
jndi的自动配置
- XADataSourceAutoConfiguration:
分布式事务相关的
(1.3) 、修改配置项
spring: datasource: url: jdbc:mysql://localhost:3306/db_account username: root password: ****** driver-class-name: com.mysql.jdbc.Driver
配置数据源成功且各项信息正确
引入了JDBC和驱动 对数据源没有进行配置
2.使用Druid数据源
HikariDataSource: 是世界上性能最好的数据源。
Druid: 是世界上安全属性最高的数据源。
(1).druid官方github地址
https://github.com/alibaba/druid
整合第三方技术的两种方式
- 自定义
- 找starter
(2).自定义方式 (使用德鲁伊数据源)
(2.1)、创建数据源
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.17</version> </dependency>
(2.2)、Spring时代配置德鲁伊数据源
1. dataSource
主要作用: 链接数据库和开启监控和防火墙等功能。
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="maxActive" value="20" /> <property name="initialSize" value="1" /> <property name="maxWait" value="60000" /> <property name="minIdle" value="1" /> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <property name="minEvictableIdleTimeMillis" value="300000" /> <property name="testWhileIdle" value="true" /> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> <property name="poolPreparedStatements" value="true" /> <property name="maxOpenPreparedStatements" value="20" />
/** * * @return 主要用途链接数据库和配置数据库信息 */ // @ConditionalOnMissingBean(DataSource.class) ->当数据中没有的话,才会使用默认的数据源 @Bean // 这里有数据源了所以使用我们配置的数据源 // @ConfigurationProperties("spring.datasource") // 因为德鲁伊的链接名和Hik的连接名一致,我们可以使用这个 public DataSource dataSource() throws SQLException { DruidDataSource druidDataSource = new DruidDataSource(); // 1.链接数据库 druidDataSource.setUrl("jdbc:mysql://localhost:3306/demo1"); druidDataSource.setUsername("root"); druidDataSource.setPassword("121788"); druidDataSource.setDriverClassName("com.mysql.jdbc.Driver"); // 2.打开SQL监控和防火墙 druidDataSource.setFilters("stat,wall"); System.out.println(druidDataSource.getClass()); return druidDataSource; }
2. 配置 StatViewServle
StatViewServlet的用途包括:
提供监控信息展示的html页面
提供监控信息的JSON API
<servlet> <servlet-name>DruidStatView</servlet-name> <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DruidStatView</servlet-name> <url-pattern>/druid/*</url-pattern> </servlet-mapping>
/** * * @return : 主要提供监控视图 和 JSON API的操作 */ @Bean public ServletRegistrationBean StatViewServlet(){ StatViewServlet statViewServlet = new StatViewServlet(); ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>(statViewServlet, "/druid/*"); return registrationBean; }
3.StatFilter
用于统计监控信息;如WEB监控
、URI监控
<filter> <filter-name>DruidWebStatFilter</filter-name> <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class> <init-param> <param-name>exclusions</param-name> <param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value> </init-param> </filter> <filter-mapping> <filter-name>DruidWebStatFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
/** * * @return WebStatFilter用于采集web-URL关联监控的数据。 */ @Bean public FilterRegistrationBean WebStatFilter(){ WebStatFilter webStatFilter = new WebStatFilter(); FilterRegistrationBean<WebStatFilter> registrationBean = new FilterRegistrationBean<>(webStatFilter); registrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); //排除这些路径 registrationBean.setUrlPatterns(Arrays.asList("/*")); // 拦截这个路径 return registrationBean; }