目录
resources 数据源文件 jdbc.properties
service.impl 业务层实现类 AccountServiceImpl.java
Spring 整合 Junit 测试类AccountServiceTest
第三方资源配置管理
以管理DataSource连接池为例讲第三方资源配置管理
管理DataSource连接池对象
管理Druid连接池[重点]
数据库准备
create database if not exists spring_db character set utf8;
use spring_db;
create table if not exists tbl_account(
id int primary key auto_increment,
name varchar(20),
money double
);
insert into tbl_account values(null,'Tom',1000);
insert into tbl_account values(null,'Jerry',1000);
添加Druid连接池依赖和数据库驱动
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
注意 : 除了上方这俩个依赖,还有spring-context依赖
配置DruidDataSource连接池Bean对象
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="username" value="root"/>
<property name="password" value="数据库密码"/>
</bean>
在测试类中从IOC容器中获取连接池对象并打印
public class SpringTest {
public static void main(String[] args) {
ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) act.getBean("dataSource");
System.out.println(dataSource);
/*{
CreateTime:"2022-12-11 19:28:02",
ActiveCount:0,
PoolingCount:0,
CreateCount:0,
DestroyCount:0,
CloseCount:0,
ConnectCount:0,
Connections:[]
}*/
}
}
管理C3P0连接池
添加c3p0连接池依赖
<!-- c3p0驱动-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
配置c3p0连接池Bean对象
<bean id="dataSourceC3P0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="user" value="root"/>
<property name="password" value="zhoulijun"/>
<property name="maxPoolSize" value="1000"/>
</bean>
在测试类中从IOC容器中获取连接池对象并打印
DataSource dataSourceC3P0 = (DataSource) act.getBean("dataSourceC3P0");
System.out.println(dataSourceC3P0);
/*com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30
, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null,
breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null,
connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName ->
1hge139at9khur1xb3g29|7d70d1b1, debugUnreturnedConnectionStackTraces -> false, description -> null,
driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false,
identityToken -> 1hge139at9khur1xb3g29|7d70d1b1, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl ->
jdbc:mysql://localhost:3306/spring_db, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0,
maxIdleTimeExcessConnections -> 0, maxPoolSize -> 1000, maxStatements -> 0, maxStatementsPerConnection -> 0,
minPoolSize -> 3, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null,
properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false,
testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]
*/
加载Properties属性文件[重点]
将数据库的连接参数抽取到一个单独的文件中, 与Spring配置文件解耦
基本用法
配置jdbc.proerties属性文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=数据库密码
在applicationContext.xml文件中开启context命名空间, 加载jdbc.properties属性文件
<context:property-placeholder location="jdbc.properties"/>
在配置连接池Bean的地方使用EL表达式获取jdbc.properties属性文件中的值
<!-- Druid 连接池Bean-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
配置不加载系统属性
问题
如果属性文件中配置的不是jdbc.username,而是username=root666,那么使用
${username}获取到的不是root666,而是计算机的名称。
原因
系统属性的优先级比我们属性文件中的高,替换了我们的username=root666。
解决
解决1:换一个名称,例如不叫username,叫jdbc.username。
解决2:使用system-properties-mode="NEVER"属性表示不使用系统属性。
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
加载properties文件
不加载系统属性
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
加载多个properties文件,逗号分隔
<context:property-placeholder location="jdbc.properties,msg.properties"/>
加载所有的properties文件 *.properties
<context:property-placeholder location="*.properties"/>
加载properties文件标准格式
<context:property-placeholder location="classpath:*.properties"/>
加载properties文件标准格式
<context:property-placeholder location="classpath*:*.properties"/>
Spring容器
Spring核心容器介绍
创建容器
方式一 : 类路径加载Spring核心配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
方式二 : 文件路径加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\applicationContext.xml");
加载多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml", "bean2.xml");
获取bean对象
方式一 : 使用bean名称获取
弊端 : 需要自己强制类型转换
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
方式二 : 使用bean名称获取并指定类型
推荐使用
BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
方式三 : 使用bean类型获取
弊端 : 如果IOC容器中同类型的bean对象有多个, 此时就会获取报错
BookDao bookDao = ctx.getBean(BookDao.class);
容器类层次结构
BeanFactory
类路径加载配置文件
Resource resources = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resources);
BookDao bookDao = bf.getBean("bookDao", BookDao.class);
bookDao.save();
BeanFactory 创建完毕后, 所有的Bean均为延迟加载, 也就是说我们调用getBean()方法获取Bean对象时才创建Bean对象并返回给我们
Spring核心容器总结
容器相关
- BeanFactory是IOC容器的顶层接口, 初始化BeanFactory对象时, 加载的bean延迟加载
- ApplicationContext接口是Spring容器的核心接口, 初始化时bean立即加载
- ApplicationContext接口提供基础的bean操作相关方法, 通过其他接口扩展其功能
- ApplicationContext接口常用初始化类
- ClassPathXmlApplicationContext(常用)
- FileSystemXmlApplicationContext
bean相关
依赖注入相关
Spring注解开发
注解开发定义bean对象[重点]
xml配置Bean对象繁琐, 使用注解简化Bean对象的定义
基本使用
在Spring核心配置文件中开启Spring注解包扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描com.itheima包及其子包下的类中注解-->
<context:component-scan base-package="priv.zlj"/>
</beans>
在类上使用@Component注解定义Bean
package priv.zlj.dao.impl;
import org.springframework.stereotype.Component;
import priv.zlj.dao.UserDao;
//@Component定义bean
@Component("userDao")
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("UserDaoImpl ==>\texecute success!" );
}
}
在测试类中获取Bean对象
public class SpringTest {
public static void main(String[] args) {
ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = act.getBean("userDao", UserDao.class);
userDao.save();
}
}
如果@Component注解没有使用参数指定Bean的名称, 那么类名首字母小写就是Bean在IOC容器中的默认名称
例如 :UserDaoImpl ==> userDaoImpl
@Component三个衍生注解
- @Controller : 用于表现层 Bean定义
- @Service : 用于业务层 Bean定义
- @Repository : 用于数据层 Bean定义
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
}
@Service
public class BookServiceImpl implements BookService {
}
纯注解开发模式[重点]
纯注解开发模式介绍
- Spring3.0 开启了纯注解开发模式, 使用Java类可以替代Spring核心配置文件.
- Java类 替代 Spring核心配置文件
public class SpringConfig {}
- @Configuration 注解用于设定当前类为配置类
@Configuration
- @ComponentScan注解用于设定扫描路径, 此注解只能添加一次, 多个数据用数组格式
@ComponentScan({"priv.zlj.service", "priv.zlj.dao"})
- 读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象
ApplicationContext act = new AnnotationConfigApplicationContext(SpringConfig.class);
代码演示
// 声明当前类为Spring配置类
@Configuration
// Spring注解扫描, 相当于<context:component-scan base-package="priv.zlj"/>
@ComponentScan("priv.zlj")
public class SpringConfig {
}
public class SpringTest {
public static void main(String[] args) {
// 加载配置类初始化容器
ApplicationContext act = new AnnotationConfigApplicationContext(SpringConfig.class);
UserDao userDao = act.getBean("userDao", UserDao.class);
userDao.save();
}
}
注解开发Bean作用范围和生命周期管理
bean作用范围注解配置
使用@scope定义bean作用范围
@Repository
@Scope("singleton")
public class BookDaoImpl implements BookDao {
}
bean生命周期注解配置
使用@PostConstruct, @preDestory定义bean的声明周期
//@Component定义bean
@Component("userDao")
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("UserDaoImpl ==>\texecute success!" );
}
@PostConstruct
public void init(){
System.out.println("init ==>\texecute success!");
}
@PreDestroy
public void destory(){
System.out.println("destory ==>\texecute success!");
}
}
注意 :
@PostConstruct和@PreDestroy注解是jdk中提供的注解,从jdk9开始,jdk中的javax.annotation包被移除了,也就是说这两个注解就用不了了,可以额外导入一下依赖解决这个问题。
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
注解开发依赖注入[重点]
使用@Autowired注解开启自动装配模式(按类型)
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
public void add() {
System.out.println("UserServiceImpl ==>\texecute success!");
userDao.save();
}
}
不管是使用配置文件还是配置类, 都必须进行对应的Spring注解包扫描才可以使用, @Autowired默认按照类型自动装配, 如果IOC容器中同类的Bean有多个, 那么默认按照变量名和Bean的名称匹配, 建议使用@Qualifier 注解指定要装配的Bean 名称
自动装配基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据, 因此无需提供setter方法
使用@Qualifier注解指定要装配的bean名称
目的 : 解决IOC容器中同类型Bean有多个装配哪一个的问题
@Service
public class BookServiceImpl implements BookService {
//@Autowired:注入引用类型,自动装配模式,默认按类型装配
@Autowired
//@Qualifier:自动装配bean时按bean名称装配
@Qualifier("bookDao")
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
注意 : @Qualifier 注解无法单独使用, 必须配合@AutoWired注解使用
使用@Value实现简单类型注入
//@Component定义bean
@Component("userDao")
public class UserDaoImpl implements UserDao {
// @value : 注入简单类型(无需提供set方法)
@Value("${jdbc.username}")
private String username;
public void save() {
System.out.println("UserDaoImpl ==>\texecute success!" );
System.out.println("UserDaoImpl property username value ==> " + username);
}
}
以上@Value注解中使用${name}从属性文件中读取name值,那么就需要在配置类或者配置文件中加载属性文件。
@Configuration
@ComponentScan("com.itheima")
//@PropertySource加载properties配置文件
@PropertySource({"classpath:jdbc.properties"}) //{}可以省略不写
public class SpringConfig {
}
使用@PropertySource注解, 可以加载属性文件
注意:@PropertySource()中加载多文件请使用数组格式配置,不允许使用通配符 *
注解开发管理第三方Bean[重点]
单独定义配置类 JdbcConfig.java
public class JdbcConfig {
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("数据库密码");
return ds;
}
}
将独立的配置类加入核心配置
方式一 : 使用@Import注解导入式
@Configuration
@ComponentScan({"priv.zlj.service", "priv.zlj.dao"})
@PropertySource("classpath:jdbc.properties")
// @Import 注解导入式
@Import({JdbcConfig.class})
public class SpringConfig {
}
方式二 : 使用@CompontentScan扫描式
@Configuration
@ComponentScan({"priv.zlj"})
@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
}
前提 : 必须在 JdbcConfig.java 添加@Configuration 注解注明此类是配置类
注解开发为第三方Bean注入资源[重点]
简单类型依赖注入
@Configuration
public class JdbcConfig {
//1.定义一个方法获得要管理的对象
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String userName;
@Value("${jdbc.password}")
private String password;
//2.@Bean:表示当前方法的返回值是一个bean对象,添加到IOC容器中
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
说明:如果@Value()中使用了EL表达式读取properties属性文件中的内容,那么就需要加载properties属性文件。
@PropertySource("classpath:jdbc.properties")
引用类型依赖注入
@Configuration
public class JdbcConfig {
//1.定义一个方法获得要管理的对象
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String userName;
@Value("${jdbc.password}")
private String password;
//2.@Bean:表示当前方法的返回值是一个bean对象,添加到IOC容器中
@Bean
public DataSource dataSource(UserDao userDao){
userDao.save();
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
说明:引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象
注解开发总结
Spring整合其他技术[重点]
Spring整合MyBatis[重点]
MyBatis程序核心对象分析
整合MyBatis
使用SqlSessionFactoryBean封装SqlSessionFactory需要的环境信息
使用MapperScannerConfigurer加载Dao接口,创建代理对象保存到IOC容器中
Spring整合Junit单元测试[重点]
导入整合的依赖坐标spring-test
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--spring整合junit-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
使用Spring整合Junit专用的类加载器
加载配置文件或者配置类
// 使用Spring整合Junit专用的类加载器
@RunWith(SpringJUnit4ClassRunner.class)
// 加载配置文件或者配置类
@ContextConfiguration(classes = {SpringConfiguration.class}) //加载配置类
//@ContextConfiguration(locations={"classpath:applicationContext.xml"})//加载配置文件
public class AccountServiceTest {
//支持自动装配注入bean
@Autowired
private AccountService accountService;
@Test
public void testFindById(){
System.out.println(accountService.findById(1));
}
@Test
public void testFindAll(){
System.out.println(accountService.findAll());
}
}
注意:junit的依赖至少要是4.12版本,可以是4.13等版本,否则出现如下异常:
Spring整合MyBatis,Junit案例
案例前准备工作
pom.xml依赖坐标
<dependencies>
<!-- Spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<!-- Druid连接池依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<!-- 数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- c3p0驱动-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- mybatis驱动-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!-- Spring 整合 jdbc驱动 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!-- Spring 整合 mybatis驱动-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--spring整合junit-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</dependencies>
实体类 Account.java
@Data
public class Account {
private Integer id;
private String name;
private Double money;
}
在实体类中我们使用了 lombok 中的 @Data 注解
@Data : 整合了Getter、Setter、ToString、EqualsAndHashCode、RequiredArgsConstructor注解。
resources 数据源文件 jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false
jdbc.username=root
jdbc.password=数据库密码
配置类 JdbcConfig.java
public class JdbcConfig {
//1.定义一个方法获得要管理的对象
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String userName;
@Value("${jdbc.password}")
private String password;
//2.@Bean:表示当前方法的返回值是一个bean对象,添加到IOC容器中
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
配置类 MyBatisConfig.java
public class MyBatisConfig {
//定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setTypeAliasesPackage("priv.zlj.pojo");
ssfb.setDataSource(dataSource);
return ssfb;
}
//定义bean,返回MapperScannerConfigurer对象
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("priv.zlj.dao");
return msc;
}
}
配置类 SpringConfig.java
@Configuration
@ComponentScan({"priv.zlj"})
@PropertySource("classpath:jdbc.properties")
// @Import 注解导入式
@Import({JdbcConfig.class,MyBatisConfig.class})
public class SpringConfig {
}
dao 数据层 AccountDao 接口
public interface AccountDao {
@Insert("insert into tbl_account(name,money)values(#{name},#{money})")
void save(Account account);
@Delete("delete from tbl_account where id = #{id} ")
void delete(Integer id);
@Update("update tbl_account set name = #{name} , money = #{money} where id = #{id} ")
void update(Account account);
@Select("select * from tbl_account")
List<Account> findAll();
@Select("select * from tbl_account where id = #{id} ")
Account findById(Integer id);
}
service 业务层 Account 接口
public interface AccountDao {
@Insert("insert into tbl_account(name,money)values(#{name},#{money})")
void save(Account account);
@Delete("delete from tbl_account where id = #{id} ")
void delete(Integer id);
@Update("update tbl_account set name = #{name} , money = #{money} where id = #{id} ")
void update(Account account);
@Select("select * from tbl_account")
List<Account> findAll();
@Select("select * from tbl_account where id = #{id} ")
Account findById(Integer id);
}
service.impl 业务层实现类 AccountServiceImpl.java
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public void save(Account account) {
accountDao.save(account);
}
public void update(Account account){
accountDao.update(account);
}
public void delete(Integer id) {
accountDao.delete(id);
}
public Account findById(Integer id) {
return accountDao.findById(id);
}
public List<Account> findAll() {
return accountDao.findAll();
}
}
Spring 整合 Junit 测试类AccountServiceTest
// 使用Spring整合Junit专用的类加载器
@RunWith(SpringJUnit4ClassRunner.class)
// 加载配置文件或者配置类
@ContextConfiguration(classes = {SpringConfig.class}) //加载配置类
//@ContextConfiguration(locations={"classpath:applicationContext.xml"})//加载配置文件
public class AccountServiceTest {
//支持自动装配注入bean
@Autowired
private AccountService accountService;
@Test
public void testFindById(){
System.out.println(accountService.findById(1));
// Account(id=1, name=Tom, money=1000.0)
}
@Test
public void testFindAll(){
System.out.println(accountService.findAll());
// [Account(id=1, name=Tom, money=1000.0), Account(id=2, name=Jerry, money=1000.0)]
}
}
Time : 2022/12/11 22:00