关于为什么jdbc配置中不能使用${username}问题,jdbc中username不生效问题,system-properties-mode取值----Spring配置jdbc的坑

文章目录

今天遇到一个坑,刚爬出来,填上以惠及他人


问题:

spring配置jdbc时,dataConfig.properties里的username不生效,jdbc配置中不能使用${username}问题



情景:

我databaseConfig.properties里的配置是这样子的

url=jdbc:mysql://localhost:3306/springstudy?characterEncoding=utf-8&serverTimezone=UTC
driverClassname=com.mysql.jdbc.Driver
username=root
password=root

下面是我xml里面的配置

    <context:property-placeholder location="databaseConfig.properties"/>
    
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
        <property name="url" value="${url}"/>
        <property name="driverClassName" value="${driverClassname}"/>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

下面是建立连接是报的错,注意第二行当中的“Access denied for user ‘Tptogiar’@‘localhost’ (using password: YES)”,其中Tptogiar是我电脑的用户名。但是我properties里面配置的是root呀,为什么最终出来的dataSource对象里面的用户名确实我电脑的用户名?

严重: create connection SQLException, url: jdbc:mysql://localhost:3306/springstudy?characterEncoding=utf-8&serverTimezone=UTC, errorCode 1045, state 28000
java.sql.SQLException: Access denied for user 'Tptogiar'@'localhost' (using password: YES)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129)
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
	at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:833)
	at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:453)
	at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:246)
	at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:198)
	at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1644)
	at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1710)
	at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2774)

为了确定我的数据库能不能连上,我写了个测试类

public class TestDruid {
    @Test
    public void testDruid() throws SQLException {
        BasicDataSource source = new  BasicDataSource();
        source.setDriverClassName( "com.mysql.jdbc.Driver" );
        source.setUrl( "jdbc:mysql:///springstudy" );
        source.setUsername( "root" );
        source.setPassword( "root" );
        Connection conn = source.getConnection();
        System.out.println(conn);
        System.out.println(conn.isClosed());
    }
}

结果输出也是正常的



发现原因:

原来在上面xml里面的配置context:property-placeholder时,如果没有指定属性system-properties-mode的值时,会默认设置为“ENVIRONMENT”。这个取值会有什么影响呢?
跟进去源码spring-context.xsd里面查看关于标签的定义。在定义里面可以发现官方对于这个property-placeholder标签里的system-properties-mode属性取值的相关说明(英文注释部分)。

	<xsd:element name="property-placeholder">
		<xsd:annotation>
			<xsd:documentation><![CDATA[
	Activates replacement of ${...} placeholders by registering a
	PropertySourcesPlaceholderConfigurer within the application context. Properties will
	be resolved against the specified properties file or Properties object -- so called
	"local properties", if any, and against the Spring Environment's current set of
	PropertySources.

	Note that as of Spring 3.1 the system-properties-mode attribute has been removed in
	favor of the more flexible PropertySources mechanism. However, applications may
	continue to use the 3.0 (and older) versions of the spring-context schema in order
	to preserve system-properties-mode behavior. In this case, the traditional
	PropertyPlaceholderConfigurer component will be registered instead of the newer
	PropertySourcesPlaceholderConfigurer.

	See ConfigurableEnvironment javadoc for more information on usage.
			]]></xsd:documentation>
			<xsd:appinfo>
				<tool:annotation>
					<tool:exports type="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
				</tool:annotation>
			</xsd:appinfo>
		</xsd:annotation>
		<xsd:complexType>
			<xsd:complexContent>
				<xsd:extension base="propertyLoading">
					<xsd:attribute name="system-properties-mode" default="ENVIRONMENT">
						<xsd:annotation>
							<xsd:documentation><![CDATA[
	Controls how to resolve placeholders against system properties. As of Spring 3.1, this
	attribute value defaults to "ENVIRONMENT", indicating that resolution of placeholders
	against system properties is handled via PropertySourcesPlaceholderConfigurer and its
	delegation to the current Spring Environment object.

	For maximum backward compatibility, this attribute is preserved going forward with the
	3.1 version of the context schema, and any values other than the default "ENVIRONMENT"
	will cause a traditional PropertyPlaceholderConfigurer to be registered instead of the
	newer PropertySourcesPlaceholderConfigurer variant. In this case, the Spring Environment
	and its property sources are not interrogated when resolving placeholders. Users are
	encouraged to consider this attribute deprecated, and to take advantage of the
	Environment and PropertySource mechanisms. See ConfigurableEnvironment javadoc for examples.

	"ENVIRONMENT" indicates placeholders should be resolved against the current Environment and against any local properties;
	"NEVER" indicates placeholders should be resolved only against local properties and never against system properties;
	"FALLBACK" indicates placeholders should be resolved against any local properties and then against system properties;
	"OVERRIDE" indicates placeholders should be resolved first against system properties and then against any local properties;
							]]></xsd:documentation>
						</xsd:annotation>
						<xsd:simpleType>
							<xsd:restriction base="xsd:string">
								<xsd:enumeration value="ENVIRONMENT"/>
								<xsd:enumeration value="NEVER"/>
								<xsd:enumeration value="FALLBACK"/>
								<xsd:enumeration value="OVERRIDE"/>
							</xsd:restriction>
						</xsd:simpleType>
					</xsd:attribute>
					<xsd:attribute name="value-separator" default=":">
						<xsd:annotation>
							<xsd:documentation><![CDATA[
	The separating character between the placeholder variable and the associated
	default value: by default, a ':' symbol.
				]]></xsd:documentation>
						</xsd:annotation>
					</xsd:attribute>
					<xsd:attribute name="trim-values">
						<xsd:annotation>
							<xsd:documentation><![CDATA[
	Whether to trim resolved values before applying them, removing superfluous
	whitespace (in particular tab characters) from the beginning and end.
				]]></xsd:documentation>
						</xsd:annotation>
					</xsd:attribute>
					<xsd:attribute name="null-value">
						<xsd:annotation>
							<xsd:documentation><![CDATA[
	A value that should be treated as 'null' when resolved as a placeholder value:
	e.g. "" (empty String) or "null". By default, no such null value is defined.
				]]></xsd:documentation>
						</xsd:annotation>
					</xsd:attribute>
				</xsd:extension>
			</xsd:complexContent>
		</xsd:complexType>
	</xsd:element>

大概的翻译一下上面源码在讲什么:

首先最外层标签xsd:element定义了一个context命名空间下(这里是在spring-context.xsd文件下)的一个property-placeholder标签,然后又定义了关于这个标签的一下其他东西。然后重点来了,在这个标签属性定义那里xsd:attribute定义了一个名为system-properties-mode的属性,然后默认值设置为ENVIRONMENT,即源码中的这部分

<xsd:attribute name="system-properties-mode" default="ENVIRONMENT">

然后我们再看一下官方关于这个属性的取值的说明,发现他说:

	"ENVIRONMENT" indicates placeholders should be resolved against the current Environment and against any local properties;
	"NEVER" indicates placeholders should be resolved only against local properties and never against system properties;
	"FALLBACK" indicates placeholders should be resolved against any local properties and then against system properties;
	"OVERRIDE" indicates placeholders should be resolved first against system properties and then against any local properties;
system-properties-mode的值取:
ENVIRONMENT
   在XML文件里面用${ }获取值的时候,会优先从本地计算机环境里面获取(这也叫说明了,为什么上文我jdbc里面username一直变为我的电脑的用户名),然后再从我们指定的properties文件里面获取
NEVER
   在XML文件里面用${ }获取值的时候,仅仅会从我们指定的properties文件里面获取
FALLBACK
   表示如果给定的配置文件properties没有该属性的话检查系统配置文件
OVERRIDE
   表示在检查特定的配置文件properties之前先检查系统配置文件






解决问题

关于jdbc配置中不能使用${username}问题,dataConfig.properties里的username不生效

通过上面我们知道当system-properties-mode去ENVIRONMENT时,解析${ }时是先回去环境里面找的,而环境里面刚好有一个key为username的值的话就会被覆盖,我们自己配置的值就会失效,所以为了避免被覆盖,换个名称就可以了

或者我们也可以直接修改system-properties-mode的取值为NEVER来避免覆盖

关于为什么jdbc配置中不能使用${username}问题,jdbc中username不生效问题,system-properties-mode取值----Spring配置jdbc的坑

上一篇:Session State Pattern会话状态模式


下一篇:2021-09-06