Spring
文章目录
控制反转 IOC
程序的耦合和解耦
- 耦合: 程序间的依赖关系.在开发中,应该做到解决编译期依赖,即编译期不依赖,运行时才依赖.
- 解耦的思路: 使用反射来创建对象,而避免使用new关键字,并通过读取配置文件来获取要创建的对象全限定类名
使用Spring解决程序耦合
准备工作
- 使用maven引入依赖,
pom.xml
如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yll</groupId>
<artifactId>Spring01</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
</project>
- 在
resources
下创建bean的配置文件bean.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--把对象的创建交给spring来管理-->
<bean id="accountDao" class="com.yll.dao.impl.AccountDaoImpl"></bean>
<bean id="accountService" class="com.yll.service.impl.AccountServiceImpl"></bean>
</beans>
- 修改表现层代码,通过Spring创建对象
/***
* 模拟表现层
*/
public class Client {
public static void main(String[] args) {
// IAccountService as = new AccountServiceImpl();
// as.saveAccount();
//1.获取核心容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.根据id获取bean对象
IAccountService as = (IAccountService) ac.getBean("accountService");
IAccountDao adao = ac.getBean("accountDao",IAccountDao.class);
System.out.println(as);
System.out.println(adao);
}
}
使用xml配置文件实现IOC
- 获取spring的IOC核心容器,并根据id获取对象
ApplicationContext方式
-
特点:
- 读取完配置文件,立马创建对象等待使用
- 单例对象使用
- 我们实际开发中使用这个,因为加载策略会随配置文件改变
-
ApplicationContext的三个常用实现类
- ClassPathXmlApplicationContext:可以加载类路径下的配置文件,要求配置文件必须在类路径下,不在,加载不了
- FileSystemXmlApplicationContext:可以加载磁盘任意路径下的配置文件(必须有访问权限)
- AnnotationConfigApplicationContext:用于读取注解创建容器
- 核心容器的两个接口引发出的问题:
- ApplicationContext: 单例对象使用
它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。一读取完配置文件马上就创建配置文件中配置的对象。 - BeanFactory: 多例对象使用
它再构建核心容器时,创建对象采取的策略是采用延迟加载的方式。什么时候根据id获取对象了,什么时候才真正创建对象
- ApplicationContext: 单例对象使用
bean标签
- 作用: 配置托管给spring的对象,默认情况下调用类的无参构造函数,若果没有无参构造函数则不能创建成功
- 属性:
id
: 指定对象在容器中的标识,将其作为参数传入getBean()方法可以获取获取对应对象.class
: 指定类的全类名,默认情况下调用无参构造函数scope
: 指定对象的作用范围,可选值如下- singleton: 单例对象,默认值
- prototype: 多例对象
- request: 将对象存入到web项目的request域中
- session: 将对象存入到web项目的session域中
- global session: 将对象存入到web项目集群的session域中,若不存在集群,则global session相当于session
init-method
:指定类中的初始化方法名称,在对象创建成功之后执行destroy-method
:指定类中销毁方法名称,对prototype多例对象没有作用,因为多利对象的销毁时机不受容器控制
bean作用范围
scope="Singleton"
单例对象- 作用范围:每个应用只有一个该对象的实例,它的作用范围就是整个应用
- 生命周期: 单例对象的创建与销毁和容器的创建与销毁时机一致
- 出生: 当应用加载,创建容器时,对象就被创建
- 活着: 只要容器存在,对象一直活着
- 死亡: 当应用卸载,销毁容器时,对象就被销毁
scope="prototype"
多例对象- 作用范围: 每次访问对象时,都会重新创建对象实例.
- 生命周期: 多例对象的创建与销毁时机不受容器控制
- 出生: 当使用对象时,创建新的对象实例
- 活着: 只要对象在使用中,就一直活着
- 死亡: 当对象长时间不用时,被 java 的垃圾回收器回收了
创建bean的三种方式
- 使用默认构造函数创建。
在spring配置文件中使用Bean标签,配以id和class属性之后,且没有其他属性和标签时。采用的就是默认构造函数创建bean对象,如果此类中没有默认构造函数,则对象无法创建。
<bean id="accountService" class="com.yll.service.impl.AccountServiceImpl"></bean>
- 必须要有
AccountServiceImpl
构造函数
/**
* 账户业务层实现类
* */
public class AccountServiceImpl implements IAccountService {
public AccountServiceImpl(){
System.out.println("accountServiceImpl构造了");
}
public void saveAccount() {
System.out.println("accountService……");
}
public void init() {
System.out.println("init……");
}
public void destory()
{
System.out.println("destory……");
}
}
- 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象。并存入spring容器)
- 创建一个工厂
public class InstanceFactory {
public IAccountService getAccountService(){
return new AccountServiceImpl();
}
}
<bean id="instanceFactory" class="com.yll.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
factory-bean
属性:指定实例工厂的idfactory-method
属性:指定实例工厂中生产对象的方法
- 使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
- 创建一个静态工厂 (静态方法不需要实例)
public class StaticFactory {
public static IAccountService getAccountService(){
return new AccountServiceImpl();
}
}
<bean id="accountService" class="com.yll.factory.StaticFactory" factory-method="getAccountService"></bean>
使用注解实现IOC
用于创建对象的注解
这些注解的作用相当于bean.xml
中的<bean>
标签
-
@Component
: 把当前类对象存入spring容器中,其属性如下:
value
: 用于指定当前类的id. 不写时默认值是当前类名,且首字母改小写 -
@Controller
: 将当前表现层对象存入spring容器中 -
@Service
: 将当前业务层对象存入spring容器中 -
@Repository
: 将当前持久层对象存入spring容器中@Controller,@Service,@Repository注解
的作用和属性与@Component
是一模一样的,可以相互替代,它们的作用是使三层对象的分别更加清晰.
用于注入数据的注解
这些注解的作用相当于bean.xml
中的<property>
标签
@Autowired
: 自动按照成员变量类型注入.- 注入过程
- 当spring容器中有且只有一个对象的类型与要注入的类型相同时,注入该对象.
- 当spring容器中有多个对象类型与要注入的类型相同时,使用要注入的变量名作为bean的id,在spring容器查找,找到则注入该对象.找不到则报错.
- 出现位置: 既可以在变量上,也可以在方法上
- 细节: 使用注解注入时,set方法可以省略
- 注入过程
@Qualifier
: 在自动按照类型注入的基础之上,再按照bean的id注入.- 出现位置: 既可以在变量上,也可以在方法上.注入变量时不能独立使用,必须和
@Autowired
一起使用; 注入方法时可以独立使用. - 属性:
value
: 指定bean的id
- 出现位置: 既可以在变量上,也可以在方法上.注入变量时不能独立使用,必须和
@Resource
: 直接按照bean的id注入,它可以独立使用.独立使用时相当于同时使用@Autowired
和@Qualifier
两个注解.- 属性:
name
: 指定bean的id
- 属性:
@Value
: 注入基本数据类型和String类型数据- 属性:
value
: 用于指定数据的值,可以使用Spel表达式(${表达式})
- 属性:
用于改变作用范围的注解
这些注解的作用相当于bean.xml
中的<bean>
标签的scope
属性
Scope
:指定bean
的作用范围- 属性
value
: 用于指定作用范围的取值"singleton","prototype","request","session","globalsession"
- 属性
和生命周期相关的注解
这些注解的作用相当于bean.xml
中的<bean>
标签的init-method
和destroy-method
属性
@PostConstruct
: 用于指定初始化方法@PreDestroy
: 用于指定销毁方法
一个例子
AccountServiceImpl类
@Service(value = "accountService")
@Scope(value = "singleton")
public class AccountServiceImpl implements IAccountService {
@Autowired
@Qualifier(value = "accountDao")
private IAccountDao accountDao;
@PostConstruct
public void init(){
System.out.println("初始化方法调用");
}
@PreDestroy
public void destroy(){
System.out.println("销毁方法调用");
}
@Override
public void saveAccount() {
accountDao.saveAccount();
}
}
表现层
public class Client {
public static void main(String[] args) {
//获取核心容器对象
AbstractApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取对象
IAccountService as = ac.getBean("accountService", IAccountService.class);
IAccountService as2 = ac.getBean("accountService", IAccountService.class);
System.out.println("是否为单例:"+as.equals(as2));
as.saveAccount();
ac.close();
}
}
bean.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"
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">
<!--告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,
而是一个名称为context名称空间和约束中-->
<context:component-scan base-package="com.yll"></context:component-scan>
</beans>
依赖注入 DI
什么是DI?
-
依赖注入(Dependency Injection)是spring框架核心ioc的具体实现.
-
通过控制反转IOC,我们把创建对象托管给了spring,但是代码中不可能消除所有依赖,例如:业务层仍然会调用持久层的方法,因此业务层类中应包含持久化层的实现类对象.我们使用框架通过配置的方式将持久层对象传入业务层,而不是直接在代码中new某个具体的持久化层实现类,这种方式称为依赖注入.
依赖注入的方法
- 因为我们是通过反射的方式来创建属性对象的,而不是使用new关键字,因此我们要指定创建出对象各字段的取值.
构造函数注入
- 使用的标签
constructor-arg
- 出现的位置:bean标签内部
- 标签的属性:
type
:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型index
:用于指定要注入的数据给构造函数中指定索引位置的参数赋值,索引位置0开始name
:用于指定给构造函数中指定名称的参数赋值
以上三个用于指定给构造函数中的哪个参数赋value
:用于提供基本类型和String类型的数据ref
:用于指定其他的bean类型数据,指的就是在spring的ioc核心容器中出现的bean对象
- 优势:
获取bean对象时,注入操作时必须的操作,否则对象无法创建 - 弊端:
改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据也必须提供
- 为要注入的类添加字段和构造函数
/**
* 账户业务层实现类
* */
public class AccountServiceImpl implements IAccountService {
//如果是经常变化的数据,并不适用于注入
private String name;
private Integer age;
private Date birthday;
public AccountServiceImpl(String name,Integer age,Date birthday){
this.name = name;
this.age = age;
this.birthday = birthday;
}
public void saveAccount() {
System.out.println("accountService……"+this.name+" "+this.age+" "+this.birthday);
}
}
- 配置
bean.xml
<bean id="accountService" class="com.yll.service.impl.AccountServiceImpl">
<constructor-arg name="name" value="test"/>
<constructor-arg name="age" value="18" />
<constructor-arg name="birthday" ref="now"/>
</bean>
<bean id="now" class="java.util.Date"></bean>
使用set注入(常用)
- 涉及的标签:
property
- 出现的位置:bean标签内部
- 标签的属性:
name
:用于指定注入时所调用的set方法名称value
:用于提供基本类型和String类型的数据ref
:用于指定其他的bean类型数据,指的就是在spring的ioc核心容器中出现的bean对象
- 优势:
创建对象时没有明确的限制,可以直接使用默认构造函数 - 弊端:
如果某个成员必须有值,则获取对象时有可能set方法没有执行
- 为要注入的类添加Setter方法
/**
* 账户业务层实现类
* */
public class AccountServiceImpl2 implements IAccountService {
//如果是经常变化的数据,并不适用于注入
private String name;
private Integer age;
private Date birthday;
public void setUserName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public void saveAccount() {
System.out.println("accountService……"+this.name+" "+this.age+" "+this.birthday);
}
}
- 配置注入
bean.xml
<bean id="accountService2" class="com.yll.service.impl.AccountServiceImpl2">
<property name="userName" value="testname"/>
<property name="age" value="20"/>
<property name="birthday" ref="now"/>
</bean>
- 这里的name属性是setXXX的XXX,不一定非要是属性名
复杂类型的注入/集合类型的注入
- 集合字段及其对应的标签按照集合的结构分为两类: 相同结构的集合标签之间可以互相替换.
- 只有键的结构:
- 数组字段:
<array>
标签表示集合,<value>
标签表示集合内的成员. - List字段:
<list>
标签表示集合,<value>
标签表示集合内的成员. - Set字段:
<set>
标签表示集合,<value>
标签表示集合内的成员.
- 数组字段:
其中<array>,<list>,<set>
标签之间可以互相替换使用.
- 键值对的结构:
- Map字段:
<map>
标签表示集合,<entry>
标签表示集合内的键值对,其key属性表示键,value属性表示值. - Properties字段:
<props>
标签表示集合,<prop>
标签表示键值对,其key属性表示键,标签内的内容表示值.
其中<map>,<props>
标签之间<entry>,<prop>
标签之间可以互相替换使用.
- Map字段:
- 为注入的类添加复杂类型(集合)字段
package com.yll.service.impl;
import com.yll.service.IAccountService;
import java.util.*;
/**
* 账户业务层实现类
* */
public class AccountServiceImpl3 implements IAccountService {
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties myProps;
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
}
public void setMylist(List<String> mylist) {
this.myList = mylist;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setMyProps(Properties myProps) {
this.myProps = myProps;
}
public void saveAccount() {
System.out.println(Arrays.toString(myStrs));
System.out.println(myList);
System.out.println(myMap);
System.out.println(mySet);
System.out.println(myProps);
}
}
- 配置
bean.xml
<bean id="accountService3" class="com.yll.service.impl.AccountServiceImpl3">
<property name="myStrs">
<array>
<value>AAAA</value>
<value>AssssAA</value>
<value>AAAsssssA</value>
</array>
</property>
<property name="mylist">
<list>
<value>list</value>
<value>asssss</value>
<value>ssss</value>
<value>ylssssssss</value>
</list>
</property>
<property name="mySet">
<set>
<value>ssssss</value>
<value>sslllss</value>
<value>ssmysetsss</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="test1" value="test1Value"></entry>
<entry key="test2" ><value>test2Value</value></entry>
</map>
</property>
<property name="myProps">
<props>
<prop key="testPro1">ssasdss</prop>
<prop key="testPro2">ssssadsasdss</prop>
</props>
</property>
</bean>
案例
纯xml配置案例
- 编写业务层
IAccountService.java
public interface IAccountService {
/**
* 查询所有
* @return
*/
List<Account> findAllAccount();
/**
* 查询一个
* @param id
* @return
*/
Account findAccountById(Integer id);
/**
* 保存操作
* @param account
*/
void saveAccount(Account account);
/**
* 更新
* @param account
*/
void updateAccount(Account account);
/**
* 删除
* @param id
*/
void deleteAccount(Integer id);
}
- 业务层实现类
AccountServiceImpl.java
,调用持久层对象的函数
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public List<Account> findAllAccount() {
return accountDao.findAllAccount();
}
@Override
public Account findAccountById(Integer id) {
return accountDao.findAccountById(id);
}
@Override
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
@Override
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
@Override
public void deleteAccount(Integer id) {
accountDao.deleteAccount(id);
}
}
- 编写持久层
IAccountDao.java
public interface IAccountDao {
/**
* 查询所有
* @return
*/
List<Account> findAllAccount();
/**
* 查询一个
* @return
*/
Account findAccountById(Integer id);
/**
* 保存操作
* @param account
*/
void saveAccount(Account account);
/**
* 更新
* @param account
*/
void updateAccount(Account account);
/**
* 删除
* @param id
*/
void deleteAccount(Integer id);
}
- 持久层实现类
AccountDaoImpl.java
,完成数据库的操作
public class AccountDaoImpl implements IAccountDao {
private QueryRunner runner;
public void setRunner(QueryRunner runner) {
this.runner = runner;
}
@Override
public List<Account> findAllAccount() {
try {
return runner.query("select * from account", new BeanListHandler<>(Account.class));
} catch (SQLException e) {
throw new RuntimeException();
}
}
@Override
public Account findAccountById(Integer id) {
try {
return runner.query("select * from account where id = ?", new BeanHandler<>(Account.class),id);
} catch (SQLException e) {
throw new RuntimeException();
}
}
@Override
public void saveAccount(Account account) {
try {
runner.update("insert into account(name,money) values(?,?)",account.getName(),account.getMoney());
} catch (SQLException e) {
throw new RuntimeException();
}
}
@Override
public void updateAccount(Account account) {
try {
runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
} catch (SQLException e) {
throw new RuntimeException();
}
}
@Override
public void deleteAccount(Integer id) {
try {
runner.update("delete from account where id=?",id);
} catch (SQLException e) {
throw new RuntimeException();
}
}
}
- 编写控制层
Account.java
/**
* 账户的实体类
*/
public class Account {
private Integer id;
private String name;
private Float money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Float getMoney() {
return money;
}
public void setMoney(Float money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
- 配置xml
bean.xml
,使用property
代表需要提供setter
方法注入
<?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">
<!--配置Service-->
<bean id="accountService" class="com.yll.service.impl.AccountServiceImpl">
<!--注入dao-->
<property name="accountDao" ref="accountDao"/>
</bean>
<!--配置Dao对象-->
<bean id="accountDao" class="com.yll.dao.impl.AccountDaoImpl">
<property name="runner" ref="queryRunner"/>
</bean>
<!--配置QueryRunner对象-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源-->
<constructor-arg name="ds" ref="dataSource"/>
</bean>
<!--配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--连接数据库的必要信息-->
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring?serverTimezone=Asia/Shanghai"/>
<property name="user" value="root"/>
<property name="password" value="52151"/>
</bean>
</beans>
- 编写测试类
/**
* 使用junit单元测试配置
*/
public class AccountServiceTest {
@Test
public void testFindAll() {
//1.获取容器
AbstractApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取业务层对象
IAccountService as = ac.getBean("accountService",IAccountService.class);
//3.执行方法
List<Account> accounts = as.findAllAccount();
accounts.forEach(System.out::println);
}
@Test
public void testFindOne() {
//1.获取容器
AbstractApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取业务层对象
IAccountService as = ac.getBean("accountService",IAccountService.class);
//3.执行方法
Account account = as.findAccountById(1);
System.out.println(account);
}
@Test
public void testSave() {
//1.获取容器
AbstractApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取业务层对象
IAccountService as = ac.getBean("accountService",IAccountService.class);
//3.执行方法
Account account = new Account();
account.setName("test");
account.setMoney(1234f);
as.saveAccount(account);
System.out.println(account);
}
@Test
public void testUpdate() {
//1.获取容器
AbstractApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取业务层对象
IAccountService as = ac.getBean("accountService",IAccountService.class);
//3.执行方法
Account account = as.findAccountById(1);
account.setMoney(555f);
as.updateAccount(account);
System.out.println(account);
}
@Test
public void testDelete() {
//1.获取容器
AbstractApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取业务层对象
IAccountService as = ac.getBean("accountService",IAccountService.class);
//3.执行方法
as.deleteAccount(3);
}
}
半注解配置案例
- 修改业务层
删除setter
,方法,改为注解形式
@Service("accountService")
public class AccountServiceImpl implements IAccountService {
@Resource(name = "accountDao")
private IAccountDao accountDao;
.....
}
- 修改持久层
删除setter
方法,改为注解形式
@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao {
@Resource(name = "queryRunner")
private QueryRunner runner;
....
}
- 修改xml配置
- 添加命名空间依赖,删除可用注解代替的
bean
标签
<?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">
<context:component-scan base-package="com.yll"/>
<!--配置QueryRunner对象-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源-->
<constructor-arg name="ds" ref="dataSource"/>
</bean>
<!--配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--连接数据库的必要信息-->
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring?serverTimezone=Asia/Shanghai"/>
<property name="user" value="root"/>
<property name="password" value="52151"/>
</bean>
</beans>
纯注解配置案例
- 新建一个总配置类
config.SpringConfiguration
,并用注解配置扫描的包和子配置类的字节码
/**
* 此类是配置类,和bean.xml作用一样
*/
@Configuration
@ComponentScan(basePackages = "com.yll")
@Import(JdbcConfig.class)
public class SpringConfiguration {
}
- 创建子配置类
config.jdbcConfiguration
,并配置properties
文件源,注入jdbc相关配置和bean
/**
* 关于数据库的配置类
*/
@Configuration
@PropertySource("classpath:jdbcConfig.properties")
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 用于创建一个QueryRunner对象
* @param dataSource 数据源
* @return 对象
*/
@Bean(name = "queryRunner")
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
/**
* 创建数据源对象
* @return
*/
@Bean(name = "dataSource")
@Scope("prototype")
public DataSource createDataSource(){
ComboPooledDataSource dataSource = new ComboPooledDataSource();
try {
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
return dataSource;
}
}
- 创建jdbc配置文件
在resources
下创建配置文件jdbcConfig.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=52151
- 修改测试类
将获取容器的实现类修改为AnnotationConfigApplicationContext
AbstractApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);