springboot配置druid连接池

2020-02-24  本文已影响0人  simba2019

Springboot配置druid数据连接池有两种方式,比较类似,但是如果搞混了容易导致部分配置不生效。

1.starter方式

这种比较简单

1.引入依赖

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.20</version>
        </dependency>

2.添加属性

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/workflow?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=workflow
spring.datasource.password=workflow
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

spring.datasource.druid.initial-size=1
spring.datasource.druid.max-active=20
spring.datasource.druid.min-idle=3
spring.datasource.druid.max-wait=60000
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
spring.datasource.druid.filters=stat,wall,slf4j
spring.datasource.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

这样启动项目就ok了。

注意,不需要自己添加新的数据连接池配置类DataSourceConfig。添加了之后可能会导致项目启动失败或者部分属性例如maxActive,minIdle等这些不生效,具体原理下面会说。

3.原理

简单说下原理,这里用到了自动装配原理。

关键是这个类

@Configuration
@ConditionalOnClass({DruidDataSource.class})
@AutoConfigureBefore({DataSourceAutoConfiguration.class})
@EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})
@Import({DruidSpringAopConfiguration.class, DruidStatViewServletConfiguration.class, DruidWebStatFilterConfiguration.class, DruidFilterConfiguration.class})
public class DruidDataSourceAutoConfigure {
    private static final Logger LOGGER = LoggerFactory.getLogger(DruidDataSourceAutoConfigure.class);

    public DruidDataSourceAutoConfigure() {
    }

    @Bean(
        initMethod = "init"
    )
    @ConditionalOnMissingBean
    public DataSource dataSource() {
        LOGGER.info("Init DruidDataSource");
        return new DruidDataSourceWrapper();
    }
}

@Configuration用于定义配置类,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

@ConditionalOnClass({DruidDataSource.class})这段可以简单理解为只有当DruidDataSource.class这个类存在时候才会实例化DruidDataSourceAutoConfigure中定义的Bean。

@AutoConfigureBefore({DataSourceAutoConfiguration.class})表示DruidDataSourceAutoConfigure要在DataSourceAutoConfiguration这个类之前加载。

@EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})表示开启自动装配属性,不需要手动set。与注解ConfigurationProperties配合使用,ConfigurationProperties负责将配置文件中的属性放到对象对应的属性中。

@Import({DruidSpringAopConfiguration.class, DruidStatViewServletConfiguration.class, DruidWebStatFilterConfiguration.class, DruidFilterConfiguration.class})表示把用到的资源导入到IOC容器中。在这里就表示将这几个类实例化为Bean后加载到IOC容器中。不仅可以导入类,也可以通过@ImportResource导入xml或者properties配置文件。

然后我们看类的实现,比较简单,除了构造方法只有一个方法public DataSource dataSource(),这个方法就是返回一个数据库连接池Bean。包含了两个注解:

@Bean( initMethod = "init" )表示返回一个Bean,同时在Bean初始化的时候要执行init这个方法。

@ConditionalOnMissingBean简单理解就是当dataSource这个Bean不存在时候才会加载这个Bean。

返回的Bean很简单就是new了一个DruidDataSourceWrapper对象。

接下来看下DruidDataSourceWrapper这个类

@ConfigurationProperties("spring.datasource.druid")
class DruidDataSourceWrapper extends DruidDataSource implements InitializingBean {
    @Autowired
    private DataSourceProperties basicProperties;

    DruidDataSourceWrapper() {
    }

    public void afterPropertiesSet() throws Exception {
        if (super.getUsername() == null) {
            super.setUsername(this.basicProperties.determineUsername());
        }

        if (super.getPassword() == null) {
            super.setPassword(this.basicProperties.determinePassword());
        }

        if (super.getUrl() == null) {
            super.setUrl(this.basicProperties.determineUrl());
        }

        if (super.getDriverClassName() == null) {
            super.setDriverClassName(this.basicProperties.getDriverClassName());
        }

    }

    @Autowired(
        required = false
    )
    public void autoAddFilters(List<Filter> filters) {
        super.filters.addAll(filters);
    }

    public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) {
        try {
            super.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
        } catch (IllegalArgumentException var4) {
            super.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
        }

    }
}

@ConfigurationProperties("spring.datasource.druid")这个注解上面已经提到就是为了自动装配属性,装配哪些属性由括号里面的决定,这里是装配配置文件中spring.datasource.druid开头的属性。看下之前的properties文件,发现主要是数据库连接池中maxActive,minIdle等这些属性。那么就会有个问题,连接池的最基础的属性url, username,password,driverClassName这些在配置文件中不是以spring.datasource.druid开头的,那么是怎么装配呢?有两种方法:

  1. 根据上面我们说的@ConfigurationProperties("spring.datasource.druid")可以装配以spring.datasource.druid开头的属性,将properties文件中这几项的配置改为:

    spring.datasource.druid.url=jdbc:mysql://localhost:3306/workflow?useUnicode=true&characterEncoding=utf-8&useSSL=false
    spring.datasource.druid.username=workflow
    spring.datasource.druid.password=workflow
    spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
    

    类似这样。这样@ConfigurationProperties("spring.datasource.druid")注解会将属性装配进来。

  2. 我们发现不修改也会装配进来,即下面这种形式也会装配进来

    spring.datasource.url=jdbc:mysql://localhost:3306/workflow?useUnicode=true&characterEncoding=utf-8&useSSL=false
    spring.datasource.username=workflow
    spring.datasource.password=workflow
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    

    为什么会这样呢?

    这与这个类DruidDataSourceWrapper里面的一个方法有关:afterPropertiesSet()

afterPropertiesSet这个方法是InitializingBean接口的实现,根据名称我们就可以猜到这个类和Bean的初始化有关系。这个方法会在Bean初始化的时候执行,并且是先于init方法执行的。具体分析我们以后文章会分析,可以关注下。

afterPropertiesSet这个方法我们看实现就是为了把url, username,password,driverClassName这几个属性放到数据连接池对象中对应的属性。就是简单的set方法,我们看到这几个属性来自于DataSourceProperties这个类的对象,那么这个类的对象从哪里获得连接的基本属性呢,看下类的实现:

@ConfigurationProperties(
    prefix = "spring.datasource"
)
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
    private ClassLoader classLoader;
    private String name;
    private boolean generateUniqueName;
    private Class<? extends DataSource> type;
    private String driverClassName;
    private String url;
    private String username;
    private String password;

类太长,我们看关键部分。

这里还是用到了@ConfigurationProperties("spring.datasource")这个注解,它负责把properties中spring.datasource开头的属性装配到类DataSourceProperties对象中对应的属性中。然后再通过afterPropertiesSet方法放到DruidDataSourceWrapper中对应的属性。

这样就会将所有的配置属性初始化到DataSourceBean中。

这种配置Druid连接池方法中用到的最关键的技术就是Springboot的自动装配原理

2.非Starter方法

  1. 引入依赖

    <dependency>
           <groupId>com.alibaba</groupId>
           <artifactId>druid</artifactId>
           <version>1.1.9</version>
    </dependency>
    
  2. 添加属性

    spring.datasource.druid.url=jdbc:mysql://localhost:3306/workflow?useUnicode=true&characterEncoding=utf-8&useSSL=false
    spring.datasource.druid.username=workflow
    spring.datasource.druid.password=workflow
    spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
    
    spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
    
    spring.datasource.druid.initial-size=1
    spring.datasource.druid.max-active=20
    spring.datasource.druid.min-idle=3
    spring.datasource.druid.max-wait=60000
    spring.datasource.druid.pool-prepared-statements=true
    spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
    spring.datasource.druid.filters=stat,wall,slf4j
    spring.datasource.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
    
  3. 添加数据源配置类

    public class DataSourceConfig {
        @Bean
        @ConfigurationProperties(prefix = "spring.datasource.druid")
        public DataSource dataSource() {
            return new DruidDataSource();
        }
    }
    

    这里要注意配置properties文件中的url, username,password,driverClassName属性的写法,是包含“druid”的,因为这里也是用到了注解@ConfigurationProperties(prefix = "spring.datasource.druid")来自动装配属性的,我们指定了自动装配以spring.datasource.druid开头的属性,如果写成spring.datasource.url则是没有办法自动装配的,属性不会生效。

    当然还有其他方法就是不使用自动装配,通过注解@Value获取到配置文件属性,然后手动用set方法将属性设置到DataSource对象对应的属性中去,这样比较麻烦,不推荐。

上一篇下一篇

猜你喜欢

热点阅读