发表于: 2021-05-08 23:04:37
3 1263
今天完成的事情:
springboot整合druid
明天计划的事情:
mybatis+thymeleaf,拆分任务4
遇到的问题:
关于spring boot没有web.xml,如何更改servlet配置的问题?
这个要看到servlet3.0 新特性
在servlet3.0的时候,servlet3.0 就已经提供了 @WebServlet,@WebFilter 等注解,这样便有了抛弃 web.xml 的第一个途径,凭借注解声明 servlet 和 filter 来做到这一点。
一个典型的 servlet3.0+ 的 web 项目结构如下,在这里CustomServletContainerInitializer 继承了 ServletContainerInitializer, 实现了 javax.servlet.ServletContainerInitializer 接口,用来在 web 容器启动时加载指定的 servlet 和 filter:
.
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── moe
│ │ └── cnkirito
│ │ ├── CustomServletContainerInitializer.java
│ │ ├── filter
│ │ │ └── HelloWorldFilter.java
│ │ └── servlet
│ │ └── HelloWorldServlet.java
│ └── resources
│ └── META-INF
│ └── services
│ └── javax.servlet.ServletContainerInitializer
└── test
└── java
public class CustomServletContainerInitializer implements ServletContainerInitializer {
private final static String JAR_HELLO_URL = "/hello";
@Override
public void onStartup(Set<Class<?>> c, ServletContext servletContext) {
System.out.println("创建 helloWorldServlet...");
ServletRegistration.Dynamic servlet = servletContext.addServlet(
HelloWorldServlet.class.getSimpleName(),
HelloWorldServlet.class);
servlet.addMapping(JAR_HELLO_URL);
System.out.println("创建 helloWorldFilter...");
FilterRegistration.Dynamic filter = servletContext.addFilter(
HelloWorldFilter.class.getSimpleName(), HelloWorldFilter.class);
EnumSet<DispatcherType> dispatcherTypes = EnumSet.allOf(DispatcherType.class);
dispatcherTypes.add(DispatcherType.REQUEST);
dispatcherTypes.add(DispatcherType.FORWARD);
filter.addMappingForUrlPatterns(dispatcherTypes, true, JAR_HELLO_URL);
}
}
Spring 是如何支持 servlet3.0 的?
通过查看源码可知,SpringServletContainerInitializer 继承了 ServletContainerInitializer
看java doc,描述:
Servlet 3.0 {@link ServletContainerInitializer} designed to support code-based configuration of the servlet container using Spring s {@link WebApplicationInitializer} SPI as opposed to (or possibly in combination with) the traditional {@code web.xml}-based approach.
Servlet 3.0 {@link ServletContainerInitializer}设计来支持使用Spring s {@link WebApplicationInitializer} SPI的基于代码的Servlet容器配置,而不是传统的{@code web.xml}基于代码的方法。
SpringBoot 如何加载 Servlet?
下面看整个过程,看的很迷糊,直接的得出结论把
使用springboot打包成war会出问题,所以springboot 没有完全遵守 servlet3.0 规范,而是使用了另一套初始化流程,TomcatStarter。
下面是这个类的运行逻辑,太绕了,
EmbeddedWebApplicationContext 的 onRefresh 方法触发配置了一个匿名的 ServletContextInitializer。
这个匿名的 ServletContextInitializer 的 onStartup 方法会去容器中搜索到了所有的 RegisterBean 并按照顺序加载到 ServletContext 中。
这个匿名的 ServletContextInitializer 最终传递给 TomcatStarter,由 TomcatStarter 的 onStartup 方法去触发 ServletContextInitializer 的 onStartup 方法,最终完成装配!
收获:
整合druid:
druid是什么?
Druid 是阿里巴巴开源平台上一个数据库连接池实现,结合了 C3P0、DBCP 等 DB 池的优点,同时加入了日志监控。
Druid 可以很好的监控 DB 池连接和 SQL 的执行情况,天生就是针对监控而生的 DB 连接池。
导入依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<!-- 日志记录 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
添加配置:
spring:
datasource:
username:
password:
#?serverTimezone=UTC解决时区的报错
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
#初始化时建立物理连接的个数
initial-size: 5
#最小连接池数量
min-idle: 5
#最大连接池数量
max-active: 20
#获取连接时最大等待时间,单位毫秒
max-wait: 60000
#既作为检测的间隔时间又作为testWhileIdel执行的依据
time-between-eviction-runs-millis: 60000
#销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接
min-evictable-idle-time-millis: 300000
validation-query: SELECT "x"
#申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
test-while-idle: true
#申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
test-on-borrow: false
#归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
test-on-return: false
#是否缓存preparedStatement
pool-prepared-statements: true
#如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority
#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
filters: stat,wall,log4j
#每个连接大小的最大池准备语句数
maxPoolPreparedStatementPerConnectionSize: 20
#使用全局数据源统计
useGlobalDataSourceStat: true
#连接属性
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
现在需要为 DruidDataSource 绑定全局配置文件中的参数,再添加到容器中,而不再使用 Spring Boot 的自动生成了;我们需要 自己添加 DruidDataSource 组件到容器中,并绑定属性;
package com.kbk.confing;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
public class DruidConfig {
/*
将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
@ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
*/
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druidDataSource() {
return new DruidDataSource();
}
}
测试一下:
package com.kbk.springboottask9;
import com.alibaba.druid.pool.DruidDataSource;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@SpringBootTest
class SpringbootDataJdbcApplicationTests {
//DI注入数据源
@Autowired
DataSource dataSource;
@Test
public void contextLoads() throws SQLException {
//看一下默认数据源
System.out.println(dataSource.getClass());
//获得连接
Connection connection = dataSource.getConnection();
System.out.println(connection);
DruidDataSource druidDataSource = (DruidDataSource) dataSource;
System.out.println("druidDataSource 数据源最大连接数:" + druidDataSource.getMaxActive());
System.out.println("druidDataSource 数据源初始化连接数:" + druidDataSource.getInitialSize());
//关闭连接
connection.close();
}
}
运行,不知道为什么这是 8和0 按照配置来说应该是 20和5
找到了,是因为没有对齐,这个对此才能实现
==========
==========
报错:
log4j:WARN No appenders could be found for logger (druid.sql.Connection).
log4j:WARN Please initialize the log4j system properly.
对日志进行配置:
登录druid,查看sql耗时:
评论