druid源码分析—DruidDataSource的基本分析(五)

DruidDataSource Spring Bean 初始化

Spring Boot项目中,我们只需要简单声明一下Druid就会自动调用,DruidDataSourceinit()方法

@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);

	//声明初始化方法。
    @Bean(initMethod = "init")
    @ConditionalOnMissingBean
    public DataSource dataSource() {
        LOGGER.info("Init DruidDataSource");
        //DruidDataSourceWrapper extend DruidDataSource
        return new DruidDataSourceWrapper();
    }
}

驱动加载

当我们设置yml携带URL时,就会将URL加载到jdbcUrl这个参数中。

spring:
  datasource:
    druid:
      username: XXXX
      password: XXXX
      url: jdbc:mysql://127.0.0.1:3306/XXXX?createDatabaseIfNotExist=true&characterEncoding=UTF-8&connectTimeout=60000&socketTimeout=60000

解析驱动,根据jdbcUrl来识别数据库类型,并加载驱动。

    protected void resolveDriver() throws SQLException {
        if (this.driver == null) {
        	//根据jdbcUrl识别数据库类型,并返回DriverClassName
            if (this.driverClass == null || this.driverClass.isEmpty()) {
                this.driverClass = JdbcUtils.getDriverClassName(this.jdbcUrl);
            }
            if (MockDriver.class.getName().equals(driverClass)) {
                driver = MockDriver.instance;
            } else if ("com.alibaba.druid.support.clickhouse.BalancedClickhouseDriver".equals(driverClass)) {
                Properties info = new Properties();
                info.put("user", username);
                info.put("password", password);
                info.putAll(connectProperties);
                driver = new BalancedClickhouseDriver(jdbcUrl, info);
            } else {
                if (jdbcUrl == null && (driverClass == null || driverClass.length() == 0)) {
                    throw new SQLException("url not set");
                }
                //通过Thread.currentThread().getContextClassLoader()来加载driver
                driver = JdbcUtils.createDriver(driverClassLoader, driverClass);
            }
        } else {
            if (this.driverClass == null) {
                this.driverClass = driver.getClass().getName();
            }
        }
    }

创建连接 createPhysicalConnection()

用户名和密码加密

通过createPhysicalConnection了解到,我们可以通过继承以下两个类对密码和用户进行加密。
但存在着问题,加密通常非常的耗时,每次创建连接都要进行一次加密验证。
如果一定要对密码和用户名做加密的话,建议设置initial-size参数为设置的线程池最大大小。减少创建连接的次数。

说明
javax.security.auth.callback.NameCallback用户名加密
com.alibaba.druid.utilDruidPasswordCallback密码加密

在YML的使用如下:

spring:
  datasource:
    druid:
      user-callback: XXX
      password-callback: XXX

校验和初始化SQL

当我们设置 connection-init-sqls,每次创建连接都会进行一次初始化执行SQL,可以用于记录连接的创建信息。
设置validation-query:,则每次创建都会进行一次校验。
设置valid-connection-checker可以实现连接重连。

spring:
  datasource:
    druid:
      connection-init-sqls: XXXX
      validation-query: XXX
      valid-connection-checker: com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker
    public PhysicalConnectionInfo createPhysicalConnection() throws SQLException {
        String url = this.getUrl();
        Properties connectProperties = getConnectProperties();

        String user;
        //判断是否有名称加密
        if (getUserCallback() != null) {
            user = getUserCallback().getName();
        } else {
            user = getUsername();
        }
        String password = getPassword();
        //获取密码加密类PasswordCallback
        PasswordCallback passwordCallback = getPasswordCallback();

		//如果密码有加密,并且继承于DruidPasswordCallback,则通过该类来获取密码password。
        if (passwordCallback != null) {
            if (passwordCallback instanceof DruidPasswordCallback) {
                DruidPasswordCallback druidPasswordCallback = (DruidPasswordCallback) passwordCallback;

                druidPasswordCallback.setUrl(url);
                druidPasswordCallback.setProperties(connectProperties);
            }

            char[] chars = passwordCallback.getPassword();
            if (chars != null) {
                password = new String(chars);
            }
        }
		//将信息加载到physicalConnectProperties进行创建连接
        Properties physicalConnectProperties = new Properties();
        if (connectProperties != null) {
            physicalConnectProperties.putAll(connectProperties);
        }

        if (user != null && user.length() != 0) {
            physicalConnectProperties.put("user", user);
        }

        if (password != null && password.length() != 0) {
            physicalConnectProperties.put("password", password);
        }

        Connection conn = null;

        long connectStartNanos = System.nanoTime();
        long connectedNanos, initedNanos, validatedNanos;

        Map<String, Object> variables = initVariants
                ? new HashMap<String, Object>()
                : null;
        Map<String, Object> globalVariables = initGlobalVariants
                ? new HashMap<String, Object>()
                : null;

        createStartNanosUpdater.set(this, connectStartNanos);
        creatingCountUpdater.incrementAndGet(this);
        try {
        	//通过getDriver().connect(url, info)来获取连接
            conn = createPhysicalConnection(url, physicalConnectProperties);
            connectedNanos = System.nanoTime();

            if (conn == null) {
                throw new SQLException("connect error, url " + url + ", driverClass " + this.driverClass);
            }
            //如果存在初始化SQL,则会去调用,设置值connection-init-sqls
            initPhysicalConnection(conn, variables, globalVariables);
            initedNanos = System.nanoTime();

            validateConnection(conn);
            validatedNanos = System.nanoTime();

            setFailContinuous(false);
            setCreateError(null);
        } catch (SQLException ex) {
            setCreateError(ex);
            JdbcUtils.close(conn);
            throw ex;
        } catch (RuntimeException ex) {
            setCreateError(ex);
            JdbcUtils.close(conn);
            throw ex;
        } catch (Error ex) {
            createErrorCountUpdater.incrementAndGet(this);
            setCreateError(ex);
            JdbcUtils.close(conn);
            throw ex;
        } finally {
            long nano = System.nanoTime() - connectStartNanos;
            createTimespan += nano;
            creatingCountUpdater.decrementAndGet(this);
        }
		//返回连接
        return new PhysicalConnectionInfo(conn, connectStartNanos, connectedNanos, initedNanos, validatedNanos, variables, globalVariables);
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值