控制反转是一种思想
控制反转是为了降低程序耦合度,提高程序扩展力,达到 OCP 原则,达到 DIP 原则
控制反转,反转的是什么?
将对象的创建权利交出去,交给第三方容器负责
将对象和对象之间关系的维护权交出去,交给第三方容器负责
控制反转这种思想如何实现呢?
DI(Dependency Injection):依赖注入
依赖注入实现了控制反转的思想
Spring通过依赖注入的方式来完成Bean管理的
Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)
依赖注入:
依赖指的是对象和对象之间的关联关系
注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系
依赖注入常见的实现方式包括两种:
第一种:set 注入
第二种:构造注入
set 注入,基于 set 方法实现的,底层会通过反射机制调用属性对应的set方法然后给属性赋值。这种方式要求属性必须对外提供 set 方法
4.0.0
org.qiu
spring-003-dependency-injection
1.0-SNAPSHOT
8
8
org.springframework
spring-context
5.3.23
junit
junit
4.13.2
test
org.apache.logging.log4j
log4j-core
2.19.0
org.apache.logging.log4j
log4j-slf4j2-impl
2.19.0
package org.qiu.spring.dao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.dao
* @date 2022-10-31-17:46
* @since 1.0
*/
public class UserDao {
private static final Logger logger = LoggerFactory.getLogger(UserDao.class);
public void insert(){
logger.info("正在保存用户数据......");
}
}
package org.qiu.spring.service;
import org.qiu.spring.dao.UserDao;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.service
* @date 2022-10-31-17:53
* @since 1.0
*/
public class UserService {
private UserDao userDao;
// 使用set方式注入,必须提供set方法。
// 反射机制要调用这个方法给属性赋值的。
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void save(){
userDao.insert();
}
}
package org.qiu.spring.test;
import org.junit.Test;
import org.qiu.spring.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.test
* @date 2022-10-31-17:55
* @since 1.0
*/
public class DITest {
@Test
public void testSetDI(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = applicationContext.getBean("userServiceBean", UserService.class);
userService.save();
}
}
运行结果:
原理解析:
通过 property 标签获取到属性名:userDao
通过属性名推断出 set 方法名:setUserDao
通过反射机制调用 setUserDao() 方法给属性赋值
property 标签的 name 是属性名。
property 标签的 ref 是要注入的 bean 对象的 id。(通过ref属性来完成 bean 的装配,这是 bean 最简单的一种装配方式。装配指的是:创建系统组件之间关联的动作)
可以把 set 方法注释掉,再测试一下:
通过测试得知,底层实际上调用了 setUserDao() 方法。所以需要确保这个方法的存在
另外,对于 property 标签来说,ref 属性也可以采用标签的方式,但使用 ref 属性是多数的:
总结:set 注入的核心实现原理:通过反射机制调用 set 方法来给属性赋值,让两个对象之间产生关系
核心原理:通过调用构造方法来给属性赋值
package org.qiu.spring.service;
import org.qiu.spring.dao.UserDao;
import org.qiu.spring.dao.VipDao;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.service
* @date 2022-11-01-20:25
* @since 1.0
*/
public class CustomerService {
private UserDao userDao;
private VipDao vipDao;
public CustomerService(UserDao userDao, VipDao vipDao) {
this.userDao = userDao;
this.vipDao = vipDao;
}
public void save(){
userDao.insert();
vipDao.insert();
}
}
@Test
public void testConstructDI(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
CustomerService service = applicationContext.getBean("csBean",CustomerService.class);
service.save();
}
运行结果:
注入外部 Bean
这种方式比较常用
注入内部 Bean
这种方式使用较少,了解即可。
注入简单类型
package org.qiu.spring.bean;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-06-07:14
* @since 1.0
*/
public class User {
private String username;
private String password;
private int age;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
'}';
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setAge(int age) {
this.age = age;
}
}
@Test
public void testSimpleTypeSet(){
ApplicationContext application = new ClassPathXmlApplicationContext("set-di.xml");
User userBean = application.getBean("userBean", User.class);
System.out.println(userBean);
}
运行结果:
分析简单类型包括哪些?
Spring 源码:BeanUtils 类
public class BeanUtils{
//.......
/**
* Check if the given type represents a "simple" property: a simple value
* type or an array of simple value types.
* See {@link #isSimpleValueType(Class)} for the definition of simple
* value type.
*
Used to determine properties to check for a "simple" dependency-check.
* @param type the type to check
* @return whether the given type represents a "simple" property
* @see org.springframework.beans.factory.support.RootBeanDefinition#DEPENDENCY_CHECK_SIMPLE
* @see org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#checkDependencies
* @see #isSimpleValueType(Class)
*/
public static boolean isSimpleProperty(Class> type) {
Assert.notNull(type, "'type' must not be null");
return isSimpleValueType(type) || (type.isArray() && isSimpleValueType(type.getComponentType()));
}
/**
* Check if the given type represents a "simple" value type: a primitive or
* primitive wrapper, an enum, a String or other CharSequence, a Number, a
* Date, a Temporal, a URI, a URL, a Locale, or a Class.
*
{@code Void} and {@code void} are not considered simple value types.
* @param type the type to check
* @return whether the given type represents a "simple" value type
* @see #isSimpleProperty(Class)
*/
public static boolean isSimpleValueType(Class> type) {
return (Void.class != type && void.class != type &&
(ClassUtils.isPrimitiveOrWrapper(type) ||
Enum.class.isAssignableFrom(type) ||
CharSequence.class.isAssignableFrom(type) ||
Number.class.isAssignableFrom(type) ||
Date.class.isAssignableFrom(type) ||
Temporal.class.isAssignableFrom(type) ||
URI.class == type ||
URL.class == type ||
Locale.class == type ||
Class.class == type));
}
//........
}
简单类型:
基本数据类型
基本数据类型对应的包装类
String 或 其他的 CharSequence 子类
Number 子类
Date 子类
URI
URL
Temporal 子类(Java8 新特性,有关于时间时区的类)
Locale
Class
另外还包括以上简单值类型对应的数组类型
package org.qiu.spring.bean;
import java.net.URI;
import java.net.URL;
import java.time.LocalDate;
import java.util.Date;
import java.util.Locale;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-06-07:37
* @since 1.0
*/
public class SimpleValueType {
public static void main(String[] args) {
System.out.println(new Date());
}
private byte b;
private short s;
private int i;
private long l;
private float f;
private double d;
private boolean flag;
private char c;
private Byte b1;
private Short s1;
private Integer i1;
private Long l1;
private Float f1;
private Double d1;
private Boolean flag1;
private Character c1;
private String str;
private Date date;
private Season season;
private URI uri;
private URL url;
private LocalDate localDate;
private Locale locale;
private Class clazz;
// 省略 setter 和 toString
}
enum Season {
SPRING, SUMMER, AUTUMN, WINTER
}
@Test
public void testAllSimpleType(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-all-simple-type.xml");
SimpleValueType simpleValueType = applicationContext.getBean("simpleValueType", SimpleValueType.class);
System.out.println(simpleValueType);
}
运行结果:
需要注意的是:
如果把 Date 当做简单类型的话,日期字符串格式不能随便写。格式必须符合 Date 的 toString() 方法格式。显然这就比较鸡肋了。如果我们提供一个这样的日期字符串:2010-10-11,在这里是无法赋值给 Date 类型的属性的。
Spring6 之后,当注入的是 URL,那么这个 url 字符串是会进行有效性检测的。如果是一个存在的 url,那就没问题。如果不存在则报错。
级联属性赋值(了解)
package org.qiu.spring.bean;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-06-08:58
* @since 1.0
*/
public class Clazz {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Clazz{" +
"name='" + name + '\'' +
'}';
}
}
package org.qiu.spring.bean;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-06-09:01
* @since 1.0
*/
public class Student {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
@Test
public void testCascade(){
ApplicationContext application = new ClassPathXmlApplicationContext("cascade.xml");
Student studentBean = application.getBean("studentBean", Student.class);
System.out.println(studentBean);
Clazz clazzBean = application.getBean("clazzBean", Clazz.class);
System.out.println(clazzBean);
}
运行结果:
package org.qiu.spring.bean;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-06-09:01
* @since 1.0
*/
public class Student {
private String name;
private Clazz clazz;
public void setClazz(Clazz clazz) {
this.clazz = clazz;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", clazz=" + clazz +
'}';
}
}
@Test
public void testCascade(){
ApplicationContext application = new ClassPathXmlApplicationContext("cascade.xml");
Student studentBean = application.getBean("studentBean", Student.class);
System.out.println(studentBean);
Clazz clazzBean = application.getBean("clazzBean", Clazz.class);
System.out.println(clazzBean);
}
运行结果:
public Clazz getClazz() {
return clazz;
}
运行结果:
注入数组
数组中的元素是简单类型
package org.qiu.spring.bean;
import java.util.Arrays;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-06-22:16
* @since 1.0
*/
public class QianDaYe {
private String[] aiHaos;
public void setAiHaos(String[] aiHaos) {
this.aiHaos = aiHaos;
}
@Override
public String toString() {
return "QianDaYe{" +
"aiHaos=" + Arrays.toString(aiHaos) +
'}';
}
}
抽烟
喝酒
烫头
@Test
public void testArray(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-array.xml");
QianDaYe yuQian = applicationContext.getBean("yuQian", QianDaYe.class);
System.out.println(yuQian);
}
运行结果:
数组中元素不是简单类型
package org.qiu.spring.bean;
import java.util.Arrays;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-06-22:16
* @since 1.0
*/
public class QianDaYe {
private String[] aiHaos;
private Woman[] women;
public void setAiHaos(String[] aiHaos) {
this.aiHaos = aiHaos;
}
public void setWomen(Woman[] women) {
this.women = women;
}
@Override
public String toString() {
return "QianDaYe{" +
"aiHaos=" + Arrays.toString(aiHaos) +
", women=" + Arrays.toString(women) +
'}';
}
}
package org.qiu.spring.bean;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-06-22:24
* @since 1.0
*/
public class Woman {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Woman{" +
"name='" + name + '\'' +
'}';
}
}
运行结果:
注入 List 集合、Set 集合
注入集合,集合中存放简单类型元素就用
标签,存放的是非简单类型元素就用 标签
package org.qiu.spring.bean;
import java.util.List;
import java.util.Set;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-07-07:12
* @since 1.0
*/
public class Person {
// 注入 List 集合
private List names;
// 注入 Set 集合
private Set addrs;
@Override
public String toString() {
return "Person{" +
"names=" + names +
", addrs=" + addrs +
'}';
}
public void setNames(List names) {
this.names = names;
}
public void setAddrs(Set addrs) {
this.addrs = addrs;
}
}
张三
张三
张三
李四
李四
王五
王五
北京
广东
上海
上海
上海
@Test
public void testCollection(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-collection.xml");
Person person = applicationContext.getBean("personBean", Person.class);
System.out.println(person);
}
运行结果:
注入 Map 集合
// 注入 Map 集合
private Map phones;
@Override
public String toString() {
return "Person{" +
"names=" + names +
", addrs=" + addrs +
", phones=" + phones +
'}';
}
运行结果:
注入 Properties 属性类对象
/**
* 注入属性类对象
* Properties 本质上也是一个 Map 集合
* Properties 的父类是 HashTable,HashTable 实现了 Map 接口
* 虽然也是一个 Map 集合,但是注入方式相似,但不同
* Properties 的 key/value 只能是 String 类型
*/
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "Person{" +
"names=" + names +
", addrs=" + addrs +
", phones=" + phones +
", properties=" + properties +
'}';
}
com.nmysql.cj.jdbc.Driver
jdbc:mysql://localhost:3306/spring
root
123
运行结果:
注入 null 和 空字符串
package org.qiu.spring.bean;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-07-07:42
* @since 1.0
*/
public class Cat {
private String name;
private int age;
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
@Test
public void testNull(){
ApplicationContext application = new ClassPathXmlApplicationContext("set-di.xml");
Cat cat = application.getBean("catBean", Cat.class);
System.out.println(cat);
}
运行结果:
不给属性值注入,默认就是 null,也可以手动注入
运行结果:
注入特殊字符
XML中有5个特殊字符,分别是:<、>、'、"、&
以上5个特殊符号在XML中会被特殊对待,会被当做XML语法的一部分进行解析,如果这些特殊符号直接出现在注入的字符串当中,会报错。
解决方案包括两种:
第一种:特殊符号使用转义字符代替。
第二种:将含有特殊符号的字符串放到: 当中。因为放在 CDATA 区中的数据不会被 XML 文件解析器解析。
5个特殊字符对应的转义字符分别是:
特殊字符 | 转义字符 |
---|---|
> | > |
< | < |
' | ' |
" | " |
& | & |
package org.qiu.spring.bean;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-07-07:58
* @since 1.0
*/
public class Math {
private String result;
public void setResult(String result) {
this.result = result;
}
@Override
public String toString() {
return "Math{" +
"result='" + result + '\'' +
'}';
}
}
@Test
public void testSpecial(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");
Math mathBean = applicationContext.getBean("mathBean", Math.class);
System.out.println(mathBean);
}
运行结果:
使用 CDATA 方式:
注意:使用CDATA时,不能使用value属性,只能使用value标签。
运行结果:
目的:简化配置
使用 p 命名空间注入的前提条件包括两个:
第一:在 XML 头部信息中添加 p 命名空间的配置信息:xmlns:p="http://www.springframework.org/schema/p"
第二:p 命名空间注入是基于 setter 方法的,所以需要对应的属性提供 setter 方法
package org.qiu.spring.bean;
import java.util.Date;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-07-08:10
* @since 1.0
*/
public class Dog {
private String name;
private int age;
private Date birth;
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", birth=" + birth +
'}';
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setBirth(Date birth) {
this.birth = birth;
}
}
@Test
public void testP(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-p.xml");
Dog dog = applicationContext.getBean("dogBean", Dog.class);
System.out.println(dog);
}
运行结果:
c 命名空间是简化构造方法注入的
使用 c 命名空间的两个前提条件:
第一:需要在 xml 配置文件头部添加信息:xmlns:c="http://www.springframework.org/schema/c"
第二:需要提供构造方法
package org.qiu.spring.bean;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-07-21:34
* @since 1.0
*/
public class People {
private String name;
private int age;
private boolean sex;
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
public People(String name, int age, boolean sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
}
@Test
public void testC(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-c.xml");
People people = applicationContext.getBean("peopleBean", People.class);
System.out.println(people);
}
运行结果:
util 命名空间让配置复用
使用util命名空间的前提是:在spring配置文件头部添加配置信息。如下:
package org.qiu.spring.bean;
import java.util.Properties;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-07-21:34
* @since 1.0
*/
public class MyDataSource1 {
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "MyDataSource1{" +
"properties=" + properties +
'}';
}
}
package org.qiu.spring.bean;
import java.util.Properties;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-07-21:34
* @since 1.0
*/
public class MyDataSource2 {
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "MyDataSource2{" +
"properties=" + properties +
'}';
}
}
com.mysql.cj.jdbc.Driver
jdbc:mysql://localhost:3306/spring
root
123456
@Test
public void testUtil(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-util.xml");
MyDataSource1 dataSource1 = applicationContext.getBean("dataSource1", MyDataSource1.class);
System.out.println(dataSource1);
MyDataSource2 dataSource2 = applicationContext.getBean("dataSource2", MyDataSource2.class);
System.out.println(dataSource2);
}
运行结果:
Spring 还可以完成自动化的注入,自动化注入又被称为自动装配。它可以根据名字进行自动装配,也可以根据类型进行自动装配
根据名称自动装配
package org.qiu.spring.dao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.dao
* @date 2022-11-05-20:40
* @since 1.0
*/
public class OrderDao {
private static final Logger logger = LoggerFactory.getLogger(OrderDao.class);
public void generate(){
logger.info("订单正在生成......");
}
}
package org.qiu.spring.service;
import org.qiu.spring.dao.OrderDao;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.service
* @date 2022-11-05-20:42
* @since 1.0
*/
public class OrderService {
private OrderDao orderDao;
public void setOrderDao(OrderDao orderDao) {
this.orderDao = orderDao;
}
/**
* 生成订单的业务方法
*/
public void generate(){
orderDao.generate();
}
}
@Test
public void testAutowire(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowire.xml");
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
orderService.generate();
}
运行结果:
根据类型自动装配
package org.qiu.spring.dao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.dao
* @date 2022-10-31-20:27
* @since 1.0
*/
public class VipDao {
private static final Logger logger = LoggerFactory.getLogger(UserDao.class);
public void insert(){
logger.info("正在保存VIP信息......");
}
}
package org.qiu.spring.dao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.dao
* @date 2022-10-31-17:46
* @since 1.0
*/
public class UserDao {
private static final Logger logger = LoggerFactory.getLogger(UserDao.class);
public void insert(){
logger.info("正在保存用户数据......");
}
}
package org.qiu.spring.service;
import org.qiu.spring.dao.UserDao;
import org.qiu.spring.dao.VipDao;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.service
* @date 2022-11-01-20:25
* @since 1.0
*/
public class CustomerService {
private UserDao userDao;
private VipDao vipDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setVipDao(VipDao vipDao) {
this.vipDao = vipDao;
}
/*
public CustomerService(UserDao userDao, VipDao vipDao) {
this.userDao = userDao;
this.vipDao = vipDao;
}
*/
public void save(){
userDao.insert();
vipDao.insert();
}
}
@Test
public void testAutowireByType(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowire.xml");
CustomerService customerService = applicationContext.getBean("cs", CustomerService.class);
customerService.save();
}
运行结果:
我们都知道编写数据源的时候是需要连接数据库的信息的,例如:driver url username password等信息。这些信息可以单独写到一个属性配置文件中,这样用户修改起来会更加的方便
第一步:写一个数据源类,提供相关属性:
package org.qiu.spring.bean;
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;
/**
* @author 秋玄
* @version 1.0
* @email [email protected]
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-09-11:01
* @since 1.0
*/
public class MyDataSource implements DataSource {
private String driver;
private String url;
private String username;
private String password;
@Override
public String toString() {
return "MyDataSource{" +
"driver='" + driver + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
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;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
// 省略实现 DataSource 接口中的方法
}
第二步:在类路径下新建 jdbc.properties 文件,并配置信息:
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/spring
username=root
password=root
第三步:在 spring 配置文件中引入 context 命名空间
第四步:在 spring 中配置使用 jdbc.properties 文件
测试程序:
@Test
public void testProperties(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-properties.xml");
MyDataSource dataSource = applicationContext.getBean("dataSource", MyDataSource.class);
System.out.println(dataSource);
}
运行结果:
一 叶 知 秋,奥 妙 玄 心