基于Spring 5.2.6.RELEASE
1、java数据源
1.1、DataSource 接口
public interface DataSource extends CommonDataSource, Wrapper {
Connection getConnection() throws SQLException;
Connection getConnection(String username, String password)
throws SQLException;
}
DataSource 接口继承了 CommonDataSource 接口。
1.2、CommonDataSource 接口
public interface CommonDataSource {
java.io.PrintWriter getLogWriter() throws SQLException;
void setLogWriter(java.io.PrintWriter out) throws SQLException;
void setLoginTimeout(int seconds) throws SQLException;
int getLoginTimeout() throws SQLException;
public Logger getParentLogger() throws SQLFeatureNotSupportedException;
}
数据源最重要的是获取链接的方法。个人认为,分析任何数据源产品,从getConnection()入手比较好。
2、Spring的数据源
2.1、DriverManagerDataSource 数据源实现类
public class DriverManagerDataSource extends AbstractDriverBasedDataSource {
public DriverManagerDataSource() {
}
public DriverManagerDataSource(String url) {
setUrl(url);
}
public DriverManagerDataSource(String url, String username, String password) {
setUrl(url);
setUsername(username);
setPassword(password);
}
public DriverManagerDataSource(String url, Properties conProps) {
setUrl(url);
setConnectionProperties(conProps);
}
public void setDriverClassName(String driverClassName) {
Assert.hasText(driverClassName, "Property 'driverClassName' must not be empty");
String driverClassNameToUse = driverClassName.trim();
try {
Class.forName(driverClassNameToUse, true, ClassUtils.getDefaultClassLoader());
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException("Could not load JDBC driver class [" + driverClassNameToUse + "]", ex);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded JDBC driver: " + driverClassNameToUse);
}
}
}
DriverManagerDataSource 继承了 AbstractDriverBasedDataSource,数据源的属性在这里定义。
2.2、AbstractDriverBasedDataSource
public abstract class AbstractDriverBasedDataSource extends AbstractDataSource {
@Nullable
private String url;
@Nullable
private String username;
@Nullable
private String password;
@Nullable
private String catalog;
@Nullable
private String schema;
@Nullable
private Properties connectionProperties;
public void setUrl(@Nullable String url) {
this.url = (url != null ? url.trim() : null);
}
@Nullable
public String getUrl() {
return this.url;
}
public void setUsername(@Nullable String username) {
this.username = username;
}
@Nullable
public String getUsername() {
return this.username;
}
public void setPassword(@Nullable String password) {
this.password = password;
}
@Nullable
public String getPassword() {
return this.password;
}
public void setCatalog(@Nullable String catalog) {
this.catalog = catalog;
}
@Nullable
public String getCatalog() {
return this.catalog;
}
public void setSchema(@Nullable String schema) {
this.schema = schema;
}
@Nullable
public String getSchema() {
return this.schema;
}
public void setConnectionProperties(@Nullable Properties connectionProperties) {
this.connectionProperties = connectionProperties;
}
@Nullable
public Properties getConnectionProperties() {
return this.connectionProperties;
}
}
AbstractDriverBasedDataSource 里面定义了数据源的一些属性,AbstractDriverBasedDataSource 继承了 AbstractDataSource,AbstractDataSource 继承了 DataSource。
2.3、AbstractDataSource
public abstract class AbstractDataSource implements DataSource {
protected final Log logger = LogFactory.getLog(getClass());
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public void setLoginTimeout(int timeout) throws SQLException {
throw new UnsupportedOperationException("setLoginTimeout");
}
@Override
public PrintWriter getLogWriter() {
throw new UnsupportedOperationException("getLogWriter");
}
@Override
public void setLogWriter(PrintWriter pw) throws SQLException {
throw new UnsupportedOperationException("setLogWriter");
}
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> iface) throws SQLException {
if (iface.isInstance(this)) {
return (T) this;
}
throw new SQLException("DataSource of type [" + getClass().getName() +
"] cannot be unwrapped as [" + iface.getName() + "]");
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return iface.isInstance(this);
}
@Override
public Logger getParentLogger() {
return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
}
}
3、获取数据源连接
AbstractDriverBasedDataSource 重写了 java的DataSource获取链接的方法。
@Override
public Connection getConnection() throws SQLException {
return getConnectionFromDriver(getUsername(), getPassword());
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return getConnectionFromDriver(username, password);
}
protected Connection getConnectionFromDriver(@Nullable String username, @Nullable String password) throws SQLException {
Properties mergedProps = new Properties();
Properties connProps = getConnectionProperties();
if (connProps != null) {
mergedProps.putAll(connProps);
}
if (username != null) {
mergedProps.setProperty("user", username);
}
if (password != null) {
mergedProps.setProperty("password", password);
}
Connection con = getConnectionFromDriver(mergedProps);
if (this.catalog != null) {
con.setCatalog(this.catalog);
}
if (this.schema != null) {
con.setSchema(this.schema);
}
return con;
}
上面的获取连接的方法委派给了这个抽象方法,具体方法由子类实现
protected abstract Connection getConnectionFromDriver(Properties props) throws SQLException;
DriverManagerDataSource 实现的获取链接方法
@Override
protected Connection getConnectionFromDriver(Properties props) throws SQLException {
String url = getUrl();
Assert.state(url != null, "'url' not set");
if (logger.isDebugEnabled()) {
logger.debug("Creating new JDBC DriverManager Connection to [" + url + "]");
}
return getConnectionFromDriverManager(url, props);
}
protected Connection getConnectionFromDriverManager(String url, Properties props) throws SQLException {
return DriverManager.getConnection(url, props);
}
public static Connection getConnection(String url,java.util.Properties info) throws SQLException {
return (getConnection(url, info, Reflection.getCallerClass()));
}
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
private static Connection getConnection(String url, java.util.Properties info, Class<?> caller) throws SQLException {
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
if(url == null) {
throw new SQLException("The url cannot be null", "08001");
}
println("DriverManager.getConnection(\"" + url + "\")");
SQLException reason = null;
for(DriverInfo aDriver : registeredDrivers) {
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
if (reason != null) {
println("getConnection failed: " + reason);
throw reason;
}
println("getConnection: no suitable driver found for "+ url);
throw new SQLException("No suitable driver found for "+ url, "08001");
}
可以看出,Spring的数据源也是实现了java的数据源接口,然后重写java DataSource 的 getConnection 方法,最终委派给 Driver,即数据源驱动去获取链接。
|