spring boot 集成组件

2023-08-31 19:07:42 浏览数 (1)

springboot在spring的基础上进行了提升,主要是减少了spring里面一成不变的xml配置。

使用约定大于配置大于代码的思想,只需要引用响应的包,进行对应的值配置即可。

下面是集成各个组件的例子。

1、集成redis

包引用

代码语言:javascript复制
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.5.12</version>

<!--        这里频繁的报Caused by: java.lang.ClassNotFoundException: com.fasterxml.jackson.core.Versioned
    也就是jackon相关的包找不到,是因为在spring-boot-starter-web中排除了,不排除即可-->
        </dependency>

配置内容

代码语言:javascript复制
spring:
  redis:
    database: 0
    host: 9.0.0.43
    port: 6379
    password: password
    jedis:
      pool:
        max-active: 1024
        max-wait: 10000
        max-idle: 200
        min-idle: 0
    timeout: 10000
    block-when-exhausted: true

这个配置是标准的配置格式,不能乱动。按照这个配置整好之后,

启动项目,@SpringBootApplication -> @EnableAutoConfiguration -> @Import({AutoConfigurationImportSelector.class})将会自动进行bean的配置,前提是有按照spring约定的格式进行配置。有哪些bean可以自动配置的呢,可参见包org.springframework.boot:spring-boot-autoconfigure/Meta-inf/spring-autoconfigure-metadata.properties。

在使用的时候,直接使用springboot的redisTemplate即可,spring中有很多template的对象,使用的是模板方法模式,即里面设计好了逻辑,只需要对应的实现或者实现自己的逻辑即可。

代码语言:javascript复制
    @Autowired
    RedisTemplate  redisTemplate;
    
    redisTemplate.opsForValue().get("aa");

如果是用spring框架的话,则需要有很多配置,可参考如https://developer.aliyun.com/article/319845(没验证)至少需要xml进行bean配置以及Configurate代码配置等。

但是标准配置也不是万能的,比如,有多个mysql库,这里就区分不了了。所以该有的还是避免不了。

2、集成mysql

包引用

代码语言:javascript复制
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.38</version>
</dependency>

配置内容

代码语言:javascript复制
spring:
  datasource:
    mysql:
      # fatp,数据源的地址
      fatp:
        username: admin
        password: password
        jdbc-url: jdbc:mysql://9.0.0.7:3306/fatp?useUnicode=true&characterEncoding=utf8&serverTimezone=Hongkong&useAffectedRows=true&autoReconnect=true&useSSL=false
        driver-class-name: com.mysql.jdbc.Driver
        pool-name: mysqlHikariCP
        register-mbeans: true
        maximum-pool-size: 10
        connection-test-query: select 1

这里可见与redis的配置数据结构不一样,是因为考虑到会有多个mysql的db配置

代码语言:javascript复制
package com.xx.fatp.dw.conf;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.HikariPoolMXBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.concurrent.TimeUnit;

@Slf4j
@Configuration
@MapperScan(basePackages = {"com.xx.dao.mysql.mapper"},
        sqlSessionTemplateRef = "mysqlSqlSessionTemplate", lazyInitialization = "true")
public class MysqlDataSourceConfig {

    private static final int MONITOR_INTERVAL_SECONDS = 5;

    /**
     * 获取数据源信息
     */
    @Bean
    public HikariConfig mysqlDataSourceProperties() {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setUsername(
                PropertiesUtils.getString("spring.datasource.mysql.fatp.username"));
        hikariConfig.setPassword(
                PropertiesUtils.getString("spring.datasource.mysql.fatp.password"));
        hikariConfig.setJdbcUrl(
                PropertiesUtils.getString("spring.datasource.mysql.fatp.jdbc-url"));
        hikariConfig.setDriverClassName(
                PropertiesUtils.getString("spring.datasource.mysql.fatp.driver-class-name"));
        hikariConfig.setPoolName(
                PropertiesUtils.getString("spring.datasource.mysql.fatp.pool-name"));
        hikariConfig.setRegisterMbeans(Boolean.parseBoolean(
                PropertiesUtils.getString("spring.datasource.mysql.fatp.register-mbeans")));
        hikariConfig.setMaximumPoolSize(
                PropertiesUtils.getInt("spring.datasource.mysql.fatp.maximum-pool-size"));
        return hikariConfig;
    }


    /**
     * 创建datasource
     */
    @Bean(name = "mysqlDataSource")
    @Lazy
    public DataSource mysqlDataSource() {
        HikariDataSource ds = new HikariDataSource(mysqlDataSourceProperties());
        log.info("database url : {}, pool size : {}", ds.getJdbcUrl(), ds.getMaximumPoolSize());

        try {
            HikariPoolMXBean poolProxy = ds.getHikariPoolMXBean();
            //连接池监控进程
            startConnectionPoolMonitor(poolProxy);

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return ds;
    }

    private void startConnectionPoolMonitor(HikariPoolMXBean poolProxy) {
        new Thread(() -> {

            while (true) {
                try {
                    if (poolProxy.getThreadsAwaitingConnection() > 0) {
                        log.info("MySQLHikariConnectionPoolState = "
                                  "Active=["   poolProxy.getActiveConnections()   "] "
                                  "Idle=["   poolProxy.getIdleConnections()   "] "
                                  "Wait=["   poolProxy.getThreadsAwaitingConnection()   "] "
                                  "Total=["   poolProxy.getTotalConnections()   "]");
                    }

                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                } finally {
                    try {
                        TimeUnit.SECONDS.sleep(MONITOR_INTERVAL_SECONDS);
                    } catch (Exception e) {
                        //do nothing
                    }
                }
            }

        }).start();
    }

    /**
     * 配置事务.
     */
    @Bean
    @Resource
    public PlatformTransactionManager mysqlManager(
            @Qualifier("mysqlDataSource") DataSource mysqlDataSource) {
        return new DataSourceTransactionManager(mysqlDataSource);
    }

    /**
     * 创建factory
     */
    @Bean
    public SqlSessionFactory mysqlSqlSessionFactory(
            @Qualifier("mysqlDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        try {
            return bean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建template
     */
    @Bean
    public SqlSessionTemplate mysqlSqlSessionTemplate(
            @Qualifier("mysqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory)
            throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

3、集成pgsql

依赖包

代码语言:javascript复制
<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.2.25</version>
</dependency>

配置

代码语言:javascript复制
spring:
  datasource:
    pgsql:
      dw:
        username: admin
        password: password
        jdbc-url: jdbc:postgresql://9.0.0.1:5432/postgres?charSet=utf-8
        driver-class-name: org.postgresql.Driver
        initialSize: 10
        maximum-pool-size: 2000
        pool-name: pgsqlHikariCP
        connection-test-query: select 1

代码语言:javascript复制
package com.xx.fatp.dw.conf;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;

@Configuration
@MapperScan(
        basePackages = "com.xx.dao.pgsql.mapper",
        sqlSessionTemplateRef = "pgsqlSqlSessionTemplate")
public class PgsqlDataSourceConfig {

    /**
     * 创建datasource
     */
    @Bean(name = "pgsqlDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.pgsql.dw")
    @Primary
    public DataSource pgsqlDataSource() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 创建factory
     */
    @Bean(name = "pgsqlSqlSessionFactory")
    @Primary
    public SqlSessionFactory pgsqlSqlSessionFactory(@Qualifier("pgsqlDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        return bean.getObject();
    }

    @Bean(name = "pgsqlTransactionManager")
    @Primary
    public DataSourceTransactionManager pgsqlTransactionManager(@Qualifier("pgsqlDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * 创建template
     */
    @Bean(name = "pgsqlSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate pgsqlSqlSessionTemplate(@Qualifier("pgsqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

4、集成mongodb

依赖包

代码语言:javascript复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
    <version>2.5.12</version>
    <exclusions>
        <exclusion>
            <artifactId>slf4j-api</artifactId>
            <groupId>org.slf4j</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-beans</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-context</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-core</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-expression</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
    </exclusions>
</dependency>

配置

代码语言:javascript复制
spring:
  datasource:
    mongodb:
      dw:
        # dw,数仓的地址
        # 需要在databse库创建对应的用户,详见fatp_rw1用户信息。
        # 角色的权限要对dbAdmin角色就不行。
        username: root
        password: password
        address: 9.0.0.121:27017
        database: fatp_dw

        下面这些暂时没有配置上,可以继续配置
        # 客户端连接池参数
        #客户端的标识,用于定位请求来源等,一般用程序名
        clientName: ${spring.application.name}
        #TCP(socket)连接超时时间,毫秒
        connectionTimeoutMs: 5000
        #TCP(socket)连接闲置时间,毫秒
        maxConnectionIdleTimeMs: 60000
        #TCP(socket)连接最多可以使用多久,毫秒
        maxConnectionLifeTimeMs: 300000
        #TCP(socket)读取超时时间,毫秒
        readTimeoutMs: 15000
        #当连接池无可用连接时客户端阻塞等待的最大时长,毫秒
        maxWaitTimeMs: 5000
        #心跳检测发送频率,毫秒
        heartbeatFrequencyMs: 20000
        #最小的心跳检测发送频率,毫秒
        minHeartbeatFrequencyMs: 8000
        #心跳检测连接超时时间,毫秒
        heartbeatConnectionTimeoutMs: 10000
        #心跳检测读取超时时间,毫秒
        heartbeatReadTimeoutMs: 15000
        #线程池允许的最大连接数
        connectionsPerHost: 100
        #线程池空闲时保持的最小连接数
        minConnectionsPerHost: 20
        #计算允许多少个线程阻塞等待时的乘数,算法:threadsAllowedToBlockForConnectionMultiplier*maxConnectionsPerHost
        threadsAllowedToBlockForConnectionMultiplier: 10

代码语言:javascript复制
package com.xx.fatp.dw.conf;

import com.mongodb.*;
import com.mongodb.client.*;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
import org.springframework.data.mongodb.core.convert.*;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableConfigurationProperties(MongodbDataSourceConfig.MongoClientOptionProperties.class)
public class MongodbDataSourceConfig {

    /**
     * 此Bean也是可以不显示定义的,如果我们没有显示定义生成MongoTemplate实例,
     * SpringBoot利用我们配置好的MongoDbFactory在配置类中生成一个MongoTemplate,
     * 之后我们就可以在项目代码中直接@Autowired了。因为用于生成MongoTemplate
     * 的MongoDbFactory是我们自己在MongoConfig配置类中生成的,所以我们自定义的连接池参数也就生效了。
     *
     * @param mongoDbFactory mongo工厂
     * @param converter      转换器
     * @return MongoTemplate实例
     */
    @Bean(name = "mongoTemplateMZ")
    public MongoTemplate mongoTemplate(MongoDatabaseFactory mongoDbFactory, MappingMongoConverter converter) {
        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory, converter);
        // 设置读从库优先
        mongoTemplate.setReadPreference(ReadPreference.secondaryPreferred());
        System.out.println("use this fuck shit");
        return mongoTemplate;
    }

    /**
     * 转换器
     * MappingMongoConverter可以自定义mongo转换器,主要自定义存取mongo数据时的一些操作,例如 mappingConverter.setTypeMapper(new
     * DefaultMongoTypeMapper(null)) 方法会将mongo数据中的_class字段去掉。
     *
     * @param factory     mongo工厂
     * @param context     上下文
     * @param conversions 自定义转换器
     * @return 转换器对象
     */
    @Bean
    public MappingMongoConverter mappingMongoConverter(MongoDatabaseFactory factory, MongoMappingContext context,
                                                       MongoCustomConversions conversions) {
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
        MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);
        mappingConverter.setCustomConversions(conversions);
        // remove _class field
        mappingConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
        return mappingConverter;
    }

    /**
     * 自定义mongo连接池
     *
     * @param properties 属性配置类
     * @return MongoDbFactory对象
     */
    @Bean
    public MongoDatabaseFactory mongoDbFactory(MongoClientOptionProperties properties) {
        // 解析获取mongo服务地址
        List<ServerAddress> serverAddressList = getServerAddress(properties.getAddress());

        // 创建认证
        MongoCredential mongoCredential = getCredential(properties);

        MongoClientSettings settings = MongoClientSettings.builder()
                .applyToClusterSettings(builder -> builder.hosts(serverAddressList))
                .credential(mongoCredential)
                .build();

        MongoClient mongoClient =  MongoClients.create(settings);

        return new SimpleMongoClientDatabaseFactory(mongoClient, properties.getDatabase());
    }

    /**
     * 创建认证
     *
     * @param properties 属性配置类
     * @return 认证对象
     */
    private MongoCredential getCredential(MongoClientOptionProperties properties) {
        if (!StringUtils.isEmpty(properties.getUsername()) && !StringUtils.isEmpty(properties.getPassword())) {
            // 没有专用认证数据库则取当前数据库
            String database = StringUtils.isEmpty(properties.getAuthenticationDatabase()) ?
                    properties.getDatabase() : properties.getAuthenticationDatabase();
            return MongoCredential.createCredential(properties.getUsername(), database,
                    properties.getPassword().toCharArray());
        }
        return null;
    }

    /**
     * 获取数据库服务地址
     *
     * @param mongoAddress 地址字符串
     * @return 服务地址数组
     */
    private List<ServerAddress> getServerAddress(String mongoAddress) {
        String[] mongoAddressArray = mongoAddress.trim().split(",");
        List<ServerAddress> serverAddressList = new ArrayList<>(4);
        for (String address : mongoAddressArray) {
            String[] hostAndPort = address.split(":");
            serverAddressList.add(new ServerAddress(hostAndPort[0], Integer.parseInt(hostAndPort[1])));
        }
        return serverAddressList;
    }

    @Data
    @ConfigurationProperties(prefix = "spring.datasource.mongodb.dw")
    public static class MongoClientOptionProperties {

        /**
         * 基础连接参数
         */
        private String database; // 要连接的数据库
        private String username; // 用户名
        private String password; // 密码
        private String address; // IP和端口(host:port),例如127.0.0.1:27017。集群模式用,分隔开,例如host1:port1,host2:port2
        private String authenticationDatabase; // 设置认证数据库,如果有的话

        /**
         * 客户端连接池参数
         */
        private String clientName; // 客户端的标识,用于定位请求来源等,一般用程序名
        private int connectionTimeoutMs; // TCP(socket)连接超时时间,毫秒
        private int maxConnectionIdleTimeMs; // TCP(socket)连接闲置时间,毫秒
        private int maxConnectionLifeTimeMs; // TCP(socket)连接最多可以使用多久,毫秒
        private int readTimeoutMs; // TCP(socket)读取超时时间,毫秒
        private int maxWaitTimeMs; // 当连接池无可用连接时客户端阻塞等待的最大时长,毫秒
        private int heartbeatFrequencyMs; // 心跳检测发送频率,毫秒
        private int minHeartbeatFrequencyMs; // 最小的心跳检测发送频率,毫秒
        private int heartbeatConnectionTimeoutMs; // 心跳检测连接超时时间,毫秒
        private int heartbeatReadTimeoutMs; // 心跳检测读取超时时间,毫秒
        private int connectionsPerHost; // 线程池允许的最大连接数
        private int minConnectionsPerHost; // 线程池空闲时保持的最小连接数
        // 计算允许多少个线程阻塞等待时的乘数,算法:threadsAllowedToBlockForConnectionMultiplier*maxConnectionsPerHost
        private int threadsAllowedToBlockForConnectionMultiplier;
    }
}

集成mongo有账号的限制

todo,可见各个db的配置,无非就是datasource - factory - template的配置,还需要详细梳理一下。

0 人点赞