依赖注入的本质
依赖注入是为了让类(对象)获得它所需要的其他类(对象)。这些依赖关系由Spring容器来处理,实现对象之间的解耦。
依赖注入 ≠ 简单的赋值
虽然依赖注入最终的效果是给对象的属性赋值,但注入不仅仅是简单的赋值,而是一种设计模式。更重要的是,它让对象之间产生关系,并且这种关系由Spring容器来管理。开发者只需声明依赖,不需要手动创建或管理依赖对象。其背后的核心思想是 控制反转(IoC, Inversion of Control),即把控制对象依赖关系的责任交给框架,而不是在代码内部自行创建对象。
外部注入和内部注入
在 Spring 框架中,set
注入用于通过 JavaBean 的 setter 方法注入依赖。Spring 提供了两种类型的 Bean 注入:内部 Bean 和 外部 Bean。它们的区别在于它们如何在 XML 配置文件中定义和使用。
1. 内部 Bean(Inner Bean)
内部 Bean 是在另一个 Bean 的定义中内联定义的 Bean,它只能用于当前的父 Bean,无法在其他地方引用。
特点:
- 只能在包含它的外部 Bean 中使用。其实就是两个嵌套的Bean。
- 由于内部 Bean 没有
id
或name
,不能在其他地方引用它。<bean id="person" class="com.example.Person"> <property name="address"> <!-- 内部 Bean 定义 --> <bean class="com.example.Address"> <property name="city" value="New York"/> <property name="zipcode" value="10001"/> </bean> </property> </bean>
2. 外部 Bean(Outer Bean)
外部 Bean 是在 Spring 容器中全局定义的 Bean,可以在多个地方引用。
特点:
- 定义在 Spring 配置文件的顶层。
- 通过
id
或name
属性,可以在多个 Bean 中共享或引用。<bean id="address" class="com.example.Address"> <property name="city" value="New York"/> <property name="zipcode" value="10001"/> </bean> <bean id="person" class="com.example.Person"> <property name="address" ref="address"/> </bean>
<property name="address" ref="address"/>
表示Person
类中的address
属性将与前面定义的address
Bean 连接(注入)在一起。注意address是一个类。具体来说,这个 XML 配置的意思是:
property
标签中的name="address"
指的是Person
类中的address
属性(假设该类中存在一个setAddress(Address address)
的 setter 方法,Spring 会调用这个方法来完成注入)。ref="address"
表示引用前面定义的名为address
的 Bean,并将其注入到Person
类中的address
属性中。
简单类型的注入:
1. 使用 <property>
标签注入简单类型
使用 Spring 的 XML 配置文件,你可以通过 <property>
标签为 Bean 的属性注入简单类型的值。
示例:注入基本数据类型
<bean id="person" class="com.example.Person">
<property name="name" value="John Doe"/>
<property name="age" value="30"/>
<property name="height" value="180.5"/>
<property name="isEmployed" value="true"/>
</bean>
对应的 Java 类:
public class Person {
private String name;
private int age;
private double height;
private boolean isEmployed;
// setter 和 getter 方法
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setHeight(double height) {
this.height = height;
}
public void setIsEmployed(boolean isEmployed) {
this.isEmployed = isEmployed;
}
// getter 方法...
}
在这个示例中:
name
是String
类型,通过value="John Doe"
进行注入。age
是int
类型,通过value="30"
进行注入。height
是double
类型,通过value="180.5"
进行注入。isEmployed
是boolean
类型,通过value="true"
进行注入。
总结
注入简单类型是通过 <property>
标签的 value
属性来完成的,Spring 会自动进行类型转换。你可以注入原始类型(如 int
、boolean
)、包装类(如 Integer
、Boolean
)、字符串和枚举类型。
简单类型有:
8个基本类型以及对应的包装类型,String类型,数组类型,枚举类型,集合类型(List,set,Map),日期类型(但是在开发中会把他当成非简单类型,因为需要遵循一定的格式,很麻烦),数字(如 Integer
、Double
)、URI、URL、Locale 等类型
简单类型注入的经典应用
运用在数据库连接的配置,方便通过 XML 文件来灵活地修改数据库连接信息。
XML代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 让spring来管理我们的数据源-->
<bean id="myDataSource" class="spring6.jdbc.myDataSource" >
<property name="driver" value="om.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/Test"/>
<property name="username" value="root"/>
<property name="password" value="gege5211314"/>
</bean>
</beans>
java示例代码
package spring6.jdbc;
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
/**
* 所有的数据源都要实现java规范:javax.sql.DataSource
* 什么是数据源:能够给你提供Connection对象的,都是数据源
*/
// 可以将数据源交给spring管理
public class myDataSource implements DataSource {
private String driver;
private String url;
private String username;
private String password;
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "myDataSource{" +
"driver='" + driver + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
@Override
public Connection getConnection() throws SQLException {
return null;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}
非简单类型
引用其他 Bean(使用 ref
)
如果要注入的属性是一个对象(而不是简单的字符串、整数等),你可以使用 ref
引用其他已经定义的 Bean。
<bean id="myAddress" class="com.example.Address">
<property name="city" value="New York"/>
<property name="zipcode" value="10001"/>
</bean>
<bean id="myPerson" class="com.example.Person">
<!-- 注入复杂类型的属性 -->
<property name="address" ref="myAddress"/>
</bean>
说明:
- 这里
myPerson
Bean 的address
属性是一个Address
类型,而不是简单的类型。通过ref
来引用另一个已经定义的myAddress
Bean。 ref="myAddress"
表示Person
对象中的address
属性使用的是myAddress
这个对象。
数组类型的引入
java代码:
package spring6.bean;
import java.util.Arrays;
public class LiPing {
private String[] habits;
// 多个女性朋友
private Woman[] women;
public Woman[] getWomen() {
return women;
}
public void setWomen(Woman[] women) {
this.women = women;
}
public String[] getHabits() {
return habits;
}
public void setHabits(String[] habits) {
this.habits = habits;
}
@Override
public String toString() {
return "LiPing{" +
"habits=" + Arrays.toString(habits) +
", women=" + Arrays.toString(women) +
'}';
}
}
Women:
package spring6.bean;
public class Woman {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Woman{" +
"name='" + name + '\'' +
'}';
}
}
XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="w1" class="spring6.bean.Woman">
<property name="name" value="小花"/>
</bean>
<bean id="w2" class="spring6.bean.Woman">
<property name="name" value="小明"/>
</bean>
<bean id="w3" class="spring6.bean.Woman">
<property name="name" value="小格"/>
</bean>
<bean id="w4" class="spring6.bean.Woman">
<property name="name" value="小亮"/>
</bean>
<bean id="hobby" class="spring6.bean.LiPing">
<!-- 数组的元素属性类型都是String简单类型-->
<property name="habits">
<array>
<value>养猫</value>
<value>给猫做饭</value>
<value>和猫说话</value>
</array>
</property>
<!--数组的类型不是简单类型了-->
<property name="women">
<array>
<ref bean="w1"/>
<ref bean="w2"/>
<ref bean="w3"/>
<ref bean="w4"/>
</array>
</property>
</bean>
</beans>
代码解析:
1. 简单类型的数组注入
在配置 LiPing
Bean 时,habits
属性是一个字符串数组,包含了几个爱好。通过 <array>
标签来定义数组,并使用 <value>
标签为数组的每个元素赋值。
<property name="habits">
<array>
<value>养猫</value>
<value>给猫做饭</value>
<value>和猫说话</value>
</array>
</property>
2. 复杂类型的数组注入
在同一个 LiPing
Bean 中,women
属性是一个 Woman
对象的数组。这里使用了 <ref>
标签来引用其他已经定义的 Woman
Bean。
<property name="women">
<array>
<ref bean="w1"/>
<ref bean="w2"/>
<ref bean="w3"/>
<ref bean="w4"/>
</array>
</property>
3. Bean 定义
多个 Woman
Bean 被定义并设置了 name
属性:
<bean id="w1" class="spring6.bean.Woman">
<property name="name" value="小花"/>
</bean>
<bean id="w2" class="spring6.bean.Woman">
<property name="name" value="小明"/>
</bean>
<bean id="w3" class="spring6.bean.Woman">
<property name="name" value="小格"/>
</bean>
<bean id="w4" class="spring6.bean.Woman">
<property name="name" value="小亮"/>
</bean>
同样对于以下的集合注入规则也是这样!!
集合
java代码:
package spring6.bean;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class Person {
private List<String> names;
private Set<String> address;
private Map<Integer,String > phones;
// 注入属性类对象
//Properties本质上也是一个Map集合
// Properties的父类Hashtable,Hashtable实现Map接口
// 虽然这个也是一个Map集合,和Map的注入方式有点像,但是不同。
// properties的key和value只能是String类型
private Properties properties;
public void setPhones(Map<Integer, String> phones) {
this.phones = phones;
}
@Override
public String toString() {
return "Person{" +
"address=" + address +
", names=" + names +
", phones=" + phones +
", properties=" + properties +
'}';
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public void setAddress(Set<String> address) {
this.address = address;
}
public void setNames(List<String> names) {
this.names = names;
}
}
1. 注入 List
集合:
<property name="names">
<list>
<value>张三</value>
<value>李四</value>
<value>王五</value>
<value>张三</value>
</list>
</property>
List
集合:使用<list>
标签定义一个有序且可重复的集合。- 这里
names
属性是一个List
类型,包含 4 个值,其中 "张三" 出现了两次,表明List
允许重复元素,并保持插入的顺序。
2. 注入 Set
集合
<property name="address">
<set>
<value>湖南</value>
<value>广东</value>
<value>重庆</value>
<value>北京</value>
</set>
</property>
Set
集合:使用<set>
标签定义一个无序且不可重复的集合。- 这里
address
属性是一个Set
类型,包含 4 个值。Set
不允许重复元素,并且它是无序的(元素的顺序不保证)。
3. 注入 Map
集合
<property name="phones">
<map>
<entry key="1" value="110"/>
<entry key="2" value="120"/>
<entry key="3" value="130"/>
<entry key="4" value="140"/>
</map>
</property>
Map
集合:使用<map>
标签注入键值对,<entry>
标签用于指定键和值。- 这里
phones
属性是一个Map
,每个<entry>
定义一个键值对。键和值都是简单类型(String
),分别对应电话的编号和电话号码。 - 注释提到如果键值对不是简单类型时,使用
key-ref
和value-ref
来引用其他 Bean。
4. 注入 Properties
集合
<property name="properties">
<props>
<prop key="driver">spring6.jdbc.myDataSource</prop>
<prop key="url">om.mysql.cj.jdbc.Driver</prop>
<prop key="username">root</prop>
<prop key="password">gege5211314</prop>
</props>
</property>
Properties
集合:使用<props>
标签来定义键值对形式的配置属性,<prop>
标签用于定义键和值。- 这里
properties
属性是一个Properties
类型,包含数据库的连接信息,如驱动、URL、用户名和密码。这是一种常见的用于配置外部属性的方式。
总结:
List
集合:使用<list>
标签注入有序且可重复的集合,如names
属性。Set
集合:使用<set>
标签注入无序且不可重复的集合,如address
属性。Map
集合:使用<map>
标签注入键值对集合,如phones
属性,可以通过key
和value
来设置简单类型的键值对,或通过key-ref
和value-ref
引用其他 Bean。Properties
集合:使用<props>
标签注入键值对形式的属性,如properties
属性,常用于注入配置数据。
注入 null
值
Spring 提供了 null
元素,用于将 null
值注入到 Bean 的属性中。
<bean id="personBean" class="spring6.bean.Person">
<property name="name">
<null/>
</property>
</bean>
解释:
- 通过
<null/>
标签,Spring 会将null
值注入到name
属性中。
注意这样有时候会报错:空指针异常。
2. 注入空字符串
注入空字符串时,直接将 value
设为空即可。
示例:
<bean id="personBean" class="spring6.bean.Person">
<property name="name" value=""/>
</bean>
解释:
<property name="name" value=""/>
表示将一个空字符串注入到name
属性中。这是处理空字符串的方式。
3. 注入特殊字符
有时候需要注入特殊字符,如 XML 中的转义字符或者特殊格式的字符串。在 XML 中,需要使用转义字符来表示一些特殊符号。
常见特殊字符及其转义方式:
<
(小于号) -<
>
(大于号) ->
&
(和符号) -&
"
(双引号) -"
'
(单引号) -'
示例:注入带有特殊字符的字符串
<bean id="personBean" class="spring6.bean.Person">
<property name="description" value="This is a "special" string with <special> characters like & and quotes."/>
</bean>
使用 <![CDATA[]]>
注入特殊符号:
<bean id="personBean" class="spring6.bean.Person">
<property name="description">
<![CDATA[This is a "special" string with <special> characters like & and quotes.]]>
</property>
</bean>
解释:
<![CDATA[]]>
是 XML 的一种语法,用于将其中的内容视为未解析的字符数据(Character Data)。XML 解析器不会解析CDATA
块内的任何内容,所有字符都会原样注入到属性中。- 在这个示例中,
description
属性中包含了双引号("
)、小于号(<
)、大于号(>
)、和符号(&
)等特殊字符。使用CDATA
包裹后,这些字符无需转义,Spring 会将它们按原样注入。
什么时候使用 <![CDATA[]]>
?
- 当你需要注入包含特殊字符的长文本时,如 HTML、XML 片段、SQL 查询语句等。
- 当注入的内容包含许多需要转义的字符,使用
CDATA
可以避免过多的手动转义,减少出错的可能性。
示例:注入包含 HTML 代码的字符串
<bean id="htmlBean" class="spring6.bean.HtmlContent">
<property name="content">
<![CDATA[
<html>
<body>
<h1>This is a heading</h1>
<p>This is a paragraph with <b>bold</b> text.</p>
</body>
</html>
]]>
</property>
</bean>
在这个示例中,content
属性包含了一个 HTML 片段。如果不用 CDATA
,这些 HTML 标签会被解析器认为是 XML 的一部分,可能导致解析错误。而使用 <![CDATA[]]>
可以让 XML 解析器忽略这些内容并将其作为纯文本处理。
p命名空间:
什么是 P 命名空间注入?
在 Spring 中,P命名空间
(P-namespace)是一种简化 XML 配置文件的方法,用于方便地为 bean 的属性进行赋值,提供了一种比传统 <property>
标签更简洁的注入方式。主要是为了简化set注入。
P命名空间注入的工作原理
通常,Spring 中的属性注入使用 <property>
标签来设置 bean 的属性,例如:
<bean id="myBean" class="com.example.MyBean">
<property name="name" value="Spring" />
<property name="age" value="30" />
</bean>
如果使用 P 命名空间,配置会变得更加简洁:
但是首先引入P命名空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Bean 配置 -->
</beans>
添加以下代码:
xmlns:p="http://www.springframework.org/schema/p"
例如,假设你有一个类 Person
,它有两个属性:name
和 age
。通过传统的 XML 配置,你的注入方式可能是这样的:
<bean id="person" class="com.example.Person">
<property name="name" value="John Doe" />
<property name="age" value="30" />
</bean>
如果启用了 P 命名空间,配置会变得简洁:
<bean id="person" class="com.example.Person" p:name="John Doe" p:age="30" />
C 命名空间
C 命名空间的工作原理
主要是为了简化构造函数注入。
通常,Spring 中的构造函数注入需要在 XML 配置文件中使用 <constructor-arg>
标签来指定参数。例如:
<bean id="person" class="com.example.Person">
<constructor-arg value="John Doe" />
<constructor-arg value="30" />
</bean>
这种方式虽然清晰,但对于参数较多的构造函数来说,配置会显得冗长。而通过引入 C 命名空间,可以用更简洁的方式来进行构造函数注入:
<bean id="person" class="com.example.Person" c:_0="John Doe" c:_1="30" />
C 命名空间的另一种方式——具名参数
如果构造函数有多个参数,并且需要按名称区分参数,还可以使用具名的方式,例如:
<bean id="person" class="com.example.Person" c:name="John Doe" c:age="30" />
如何启用 C 命名空间
要使用 C 命名空间,和 P 命名空间一样,你需要在 XML 文件中引入它:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Bean 配置 -->
</beans>
util命名空间
在 Spring 框架中,util
命名空间 提供了一些辅助工具类,用于在 XML 配置中更方便地处理集合、属性文件等数据结构。这使得我们能够在 XML 配置中定义集合类型(如列表、集合、映射、属性等),并通过 util
命名空间注入到 Spring 的 bean 中。
util
命名空间的用途
util
命名空间主要用于处理以下场景:
- 定义集合(List、Set、Map)
- 定义属性文件(
Properties
对象) - 引用外部集合
- 提供简化的集合和属性文件的注入
如何启用 util
命名空间
首先,你需要在 XML 配置文件中引入 util
命名空间:把所有的beans换成util
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<!-- Bean 配置 -->
</beans>
1. 使用 util:list
注入 List
你可以使用 util:list
来定义一个 List
类型的集合,并将其注入到 bean 中:
// 对于简单类型
<util:list id="myList">
<value>Element1</value>
<value>Element2</value>
<value>Element3</value>
</util:list>
// 对于非简单类型
<bean id="myBean" class="com.example.MyBean">
<property name="list" ref="myList" />
</bean>
在此例中,myList
是一个 List
集合,它可以通过 ref
被注入到 myBean
的 list
属性中。
2. 使用 util:set
注入 Set
类似于 List
,你可以使用 util:set
来定义一个 Set
集合:
<util:set id="mySet">
<value>Element1</value>
<value>Element2</value>
</util:set>
<bean id="myBean" class="com.example.MyBean">
<property name="set" ref="mySet" />
</bean>
3. 使用 util:map
注入 Map
util:map
用于定义 Map
类型的键值对集合
<util:map id="myMap">
<entry key="key1" value="value1" />
<entry key="key2" value="value2" />
</util:map>
<bean id="myBean" class="com.example.MyBean">
<property name="map" ref="myMap" />
</bean>
基于XML的自动装配
根据名称自动装配(byName):
工作原理:
byName
自动装配会根据属性名称来匹配 Spring 容器中的 bean。如果 bean 的属性名和容器中的某个 bean 的 ID 相同,那么 Spring 会将该 bean 自动注入到这个属性中。
配置方法:
在 XML 配置中,使用 <bean>
元素的 autowire
属性将其设置为 byName
。
示例:
假设我们有两个类 Person
和 Address
,Person
类依赖于 Address
:
public class Person {
private Address address;
// setter method
public void setAddress(Address address) {
this.address = address;
}
}
public class Address {
private String city;
public Address(String city) {
this.city = city;
}
// getter and setter
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
XML 配置文件如下:
<bean id="address" class="com.example.Address">
<constructor-arg value="New York" />
</bean>
<bean id="person" class="com.example.Person" autowire="byName" />
在这个配置中,Spring 会根据 Person
类中属性 address
的名称,自动找到容器中 ID 为 address
的 bean,并注入到 person
的 address
属性中。
优点:
- 自动根据属性名称匹配 bean,配置较为简单。
注意事项:
- 如果 Spring 容器中没有与属性名称匹配的 bean,属性将不会被注入,且不会抛出异常(默认行为是属性值保持为
null
)。 - 如果属性名称和 bean ID 不匹配,需要显式使用
<property>
标签手动注入。
2. byType
自动装配
工作原理:
byType
自动装配会根据属性的类型来匹配 Spring 容器中的 bean。如果容器中存在与属性类型匹配的 bean,则 Spring 会将该 bean 自动注入到该属性中。
配置方法:
在 XML 配置中,使用 <bean>
元素的 autowire
属性将其设置为 byType
。
示例:
假设我们有相同的 Person
和 Address
类
XML 配置文件如下:
<bean id="homeAddress" class="com.example.Address">
<constructor-arg value="New York" />
</bean>
<bean id="person" class="com.example.Person" autowire="byType" />
在此配置中,Spring 会根据 Person
类中属性 address
的类型 Address
,自动找到容器中类型为 Address
的 bean,并将其注入到 person
的 address
属性中。
优点:
- 根据类型自动匹配 bean,避免了硬编码的 ID 匹配。
注意事项:
- 如果容器中存在多个相同类型的 bean,Spring 将抛出异常,因为它不知道该注入哪一个 bean。为避免这个问题,可以使用
@Primary
注解或qualifier
来指明注入的 bean。 - 如果没有匹配的类型,Spring 将不会注入该属性,并可能导致空指针异常。
byName
与 byType
的对比
特性 | byName | byType |
---|---|---|
匹配方式 | 根据属性名称和 bean ID 匹配 | 根据属性的类型和 bean 类型匹配 |
适用场景 | 当容器中存在多个相同类型但名称不同的 bean 时使用 | 当容器中只有一个特定类型的 bean 时效果更好 |
配置简洁性 | 需要 bean 的 ID 与属性名相同 | 不依赖名称,只依赖类型 |
缺点 | 名称匹配失败时,不会注入属性 | 存在多个相同类型的 bean 时会抛出异常 |
Spring引入外部属性配置文件
我们都知道编写数据源的时候是需要连接数据库的信息的,例如:driver url username password等信息。这些信息可以单独写到一个属性配置文件中吗,这样用户修改起来会更加的方便。当然可以。 第一步:写一个数据源类,提供相关属性。
package spring6.jdbc;
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
/**
* 所有的数据源都要实现java规范:javax.sql.DataSource
* 什么是数据源:能够给你提供Connection对象的,都是数据源
*/
// 可以将数据源交给spring管理
public class myDataSource implements DataSource {
private String driver;
private String url;
private String username;
private String password;
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "myDataSource{" +
"driver='" + driver + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
@Override
public Connection getConnection() throws SQLException {
return null;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}
第二步:在类路径下新建jdbc.properties文件,并配置信息。
driverClass=om.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root // 自己的数据库密码
第三步:在spring配置文件中引入context命名空间。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<beans/>
第四步:在spring中配置使用jdbc.properties文件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--引入外部的properties文件-->
<!-- 第一步:引入Context命名空间
第二步:使用标签context:property-placeholder的location属性配置文件的路径
location默认从类的根路径开始加载资源
-->
<context:property-placeholder location="jdbc.properties"/>
<bean id="ds" class="spring6.jdbc.myDataSource" >
<property name="driver" value="${driverClass}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>