预备知识:MyBatis
Spring框架-上篇
文章目录
- 注解开发
- 注解开发定义bean
- 纯注解开发
- bean管理
- bean作用范围、生命周期
- 依赖注入
- 自动装配
- 加载properties文件
- 第三方bean
- 第三方bean管理
- 第三方bean依赖注入
- 总结
- Spring整合MyBatis
- 小结
- 整合junit
- ==AOP==
- AOP简介
- AOP核心概念
- AOP入门案例思路分析
- 小结
- AOP工作流程
- AOP核心概念2
- AOP切入点表达式
- AOP通知类型
- 案例:测量业务层接口万次执行效率
- AOP通知获取数据
- 案例:百度网盘密码数据兼容处理
- AOP总结
- Spring事务
- Spring事务简介
- 案例:银行账户转账
- spring事务角色
- 事务相关配置
- 案例:转账业务追加日志
- 事务传播行为
注解开发
注解开发定义bean
- 使用@Component定义bean
//直接用注解定义bean
@Component("bookDao")//可以指定名称
public class BookDaoImpl implements BookDao{}
@Component
public class BookServiceImpl implements BookService{}
- 核心配置文件中通过组件扫描加载bean
# applicationContext.xml
// 配置后才能扫描到组件来加载bean
<context:component-scan base-package="com.itheima"/>
# App
ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocation:"applicationContext.xml");
BookDaobookDao = (BookDao)ctx.getBean("bookDao");
System.out.println(bookDao);
BookService bookService = ctx.getBean(BookService.class);//没有指定名称,用类型查找
System.out.println(bookService);
- Spring提供@Component注解的三个衍生注解
@Controller:用于表现层bean定义
@Service:用于业务层bean定义
@Repository:用于数据层bean定义
//定义数据层的bean
@Repository("bookDao")
public class BookDaoImpl implements BookDao{}
//定义服务层的bean
@Service
public class BookServiceImpl implements BookService{}
纯注解开发
- Spring3.开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道
- Java类代替Spring核心配置文件,
<?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">
<context:component-scan base-package="com.itheima"/>
</beans>
---------被代替(@ComponentScan == context:,@Configuration == 其他的配置)--------->
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig{}
- @Configuration注解用于设定当前类为配置类
- @ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
@ComponentScan({"com.itheima.service","com.itheima.dao"})
- 读取Spring核心配置文件初始化容器对象切换为读取]ava配置类初始化容器对象
//加载**配置文件**初始化容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//加载**配置类**初始化容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
bean管理
bean作用范围、生命周期
- 使用 @Scope 定义bean作用范围
- 使用 @PostConstruct、@PreDestroy 定义bean生命周期
@Repository
@Scope("singleton")//单例singleton,非单例prototype
public class BookDaoImpl implements BookDao{
public BookDaoImp1(){
System.out.println("book dao constructor ...")
)
@PostConstruct
public void init(){
System.out.println("book init ...")
)
@PreDestroy
public void destroy(){
System.out.println("book destory ...")
)
}
依赖注入
自动装配
-
使用 @Autowired 注解开启自动装配模式(按类型)
@Service public class BookServiceImpl implements BookService{ @Autowired private BookDaobookDao; ~~public void setBookDao(BookDao bookDao){ this.bookDao bookDao; }~~ //不需要了 public void save(){ System.out.println("book service save ...") bookDao.save(); } }
- 注意:自动装配基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此无需提供setter方法
- 注意:自动装配建议使用无参构造方法创建对象(默认),如果不提供对应构造方法,请提供唯一的构造方法
-
使用 @Qualifieri 注解开启指定名称装配bean
@Service public class BookServiceImpl implements BookService{ @Autowired @Qualifier("bookDao") private BookDao bookDao; }
- 注意:@Qualifier注解无法单独使用,必须配合@Autowired注解使用
-
使用@Value实现简单类型注入
@Repository("bookDao")
public class BookDaoImpl implements BookDao{
@Value("100")
private String connectionNum;
}
加载properties文件
- 使用 @PropertySource 注解加载properties文件
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
public class SpringConfig{}
- 注意:路径仅支持单一文件配置,多文件请使用数组格式配置{“”,“”, …},不允许使用通配符*
第三方bean
第三方bean管理
SpringConfig是核心配置类
JdbcConfig是独立的配置类
- 使用@Bean配置第三方bean
- 可以直接写在核心配置文件中,但推荐写成独立的配置类
@Configuration
public class SpringConfig{
@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("root");
return ds;
}
}
- 使用独立的配置类管理第三方bean
//这里不用写Configuration,用import导入
public class JdbcConfig{
@Bean
public DataSourcedataSource(){
DruidDataSource ds new DruidDataSource();
ds.setDriverclassName("com.mysql.jdbc.Driver");
ds.setur1("jdbc:mysq1://localhost:3306/spring_db");
ds.setusername("root");
ds.setPassword("root");
return ds;
}
}
- 将独立的配置类加入核心配置
-
方式一:导入式
public class JdbcConfig{ @Bean public DataSource dataSource(){ DruidDataSource ds = new DruidDataSource(); //相关配置 return ds; } }
- 使用@Import注解手动加入配置类到核心配置,此注解只能添加一次,多个数据请用数组格式{ , , }
@Configuration @Import(JdbcConfig.class) public class SpringConfig{}
-
方式二:扫描式(不推荐,因为不能确定ComponentScan加载了哪些配置类)
**@Configuration** public class JdbcConfig{ @Bean public DataSource dataSource(){ DruidDataSource ds new DruidDataSource(); //相关配置 return ds; } }
- 使用@ComponentScan注解扫描配置类所在的包,加载对应的配置类信息
@Configuration @ComponentScan({"com.itheima.config","com.itheima.service","com.itheima.dao"}) public class SpringConfig{}
-
第三方bean依赖注入
-
简单类型依赖注入
public class JdbcConfig @Value("com.mysql.jdbc.Driver") private String driver; @Value("jdbc:mysq1://localhost:3306/spring_db") private String url; @Value("root") private String userName; @Value("root") private String password; @Bean public DataSource dataSource(){ DruidDataSource ds new DruidDataSource(); ds.setDriverclassName(driver); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(userName); return ds; } }
-
引用类型依赖注入
@Bean public DataSource dataSource(BookService bookService){ System.out.println(bookService); DruidDataSource ds new DruidDataSource(); //属性设置 return ds; }
- 引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象(被注入的bean对象要已经定义)
总结
-
注解开发
- 1.定义bean
- @Component
- @Controller
- @Service
- @Repository
<context:component-scan/>
- @Component
- 2.纯注解开发
- @Configuration
- @ComponentScan
- AnnotationConfigApplicationContext
- 1.定义bean
-
bean管理
- 1.bean作用范围
- @Scope
- 2.bean生命周期
- @PostConstruct
- @PreDestroy
- 1.bean作用范围
-
依赖注入
- 1.自动装配
- @Autowired
- @Qualifier
- @Value
- 2.读取properties.文件
- @PropertySource
- 1.自动装配
-
第三方bean
- 1.第三方bean管理
- @Bean
- 2.第三方bean依赖注入
- 引用类型:方法形参
- 简单类型:成员变量
- 1.第三方bean管理
-
ML配置比对注解配置
Spring整合MyBatis
小结
1.整合MyBatis
- SqlSessionFactoryBean
- MapperScannerConfigurer
整合junit
AOP
AOP简介
- AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构
- OOP(Object Oriented Programming)面向对象编程
- 作用:在不惊动原始设计的基础上为其进行功能增强
- 可以为其他操作计算时间
- 可以为其他操作计算时间
- Spring理念:无入侵式/无侵入式
AOP核心概念
- 连接点(]oinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
- 在SpringAOP中,理解为方法的执行
- 切入点(Pointcut):匹配连接点的式子(连接点大)
- 在SpringA0P中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
- 一个具体方法:com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
- 匹配多个方法:所有的sve方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
- 在SpringA0P中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
- 通知(Advice):在切入点处执行的操作,也就是共性功能
- 在SpringAOP中,功能最终以方法的形式呈现
- 通知类:定义通知的类
- 切面(Aspect):描述通知与切入点的对应关系
AOP入门案例思路分析
- 案例设定:测定接口执行效率
- 简化设定:在接口执行前输出当前系统时间
- 开发模式:XML or 注解
- 思路分析
1.导入坐标(pom.xm1)
2.制作连接点方法(原始操作,Dao接口与实现类)
3.制作共性功能(通知类与通知)
4.定义切入点
5.绑定切入点与通知关系(切面)
小结
AOP工作流程
1.Spring容器启动
2.读取所有切面配置中的切入点
3.初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
- 匹配失败,创建对象
- 匹配成功,创建原始对象(目标对象)的代理对象
4.获取bean执行方法
- 获取bean,调用方法并执行,完成操作
- 获取的bea是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作
- 直接获取对象,代理对象和bean对象是一样的(重写了tostring),.class才是不一样
AOP核心概念2
- 目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的
- 代理(Proy):目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现
- 3.SpringAOP本质:代理模式
AOP切入点表达式
- 切入点:要进行增强的方法
- 切入点表达式:要进行增强的方法的描述方式
- 切入点表达式标准格式:动作关键字(访问修饰符返回值包名.类/接口名.方法名(参数)异常名)
*必须有一个
…可以没有/多个
- 书写技巧
- 所有代码按照标准规范开发,否则以下技巧全部失效
- 描述切入点通常描述接口,而不描述实现类
- 访问控制修饰符针对接口开发均采用oublic描述(可省略访问控制修饰符描述)
- 返回值类型对于增删改类使用精准类型加速匹配,对于查询类使用 * 通配快速描述
- 包名书写尽量不使用…匹配,效率过低,常用 * 做单个包描述匹配,或精准匹配
- 接口名/类名书写名称与模块相关的采用 * 匹配,例如UserService书写成 * Service,绑定业务层接口名
- 方法名书写以动词进行精准匹配,名词采用 * 匹配,例如getByld书写成getBy * ,selectAll-书写成selectAll
- 参数规则较为复杂,根据业务方法灵活调整
- 通常不使用异常作为匹配规则
AOP通知类型
- AOP通知描述了抽取的共性功能,根据共性功能抽取的位置不同,最终运行代码时要将其加入到合理的位置
- A0P通知共分为5种类型
- 前置通知
- 后置通知
- 环绕通知(重点)》
- 返回后通知(了解)
- 抛出异常后通知(了解)
案例:测量业务层接口万次执行效率
- 案例
测量业务层接口执行效率
需求:任意业务层接口执行均可显示其执行效率(执行时长)
分析:
①:业务功能:业务层接口执行前后分别记录时间,求差值得到执行效率
②:通知类型选择前后均可以增强的类型—环绕通知
AOP通知获取数据
- 获取切入点方法的参数
- JoinPoint:适用于前置、后置、返回后、抛出异常后通知
- ProceedJointPoint:适用于环绕通知
- 获取切入点方法返回值
- 返回后通知
- 环绕通知
- 获取切入点方法运行异常信息
- 抛出异常后通知
- 环绕通知
案例:百度网盘密码数据兼容处理
- 百度网盘分享链接输入密码数据错误兼容性处理
AOP总结
- 概念:AOP(Aspect Oriented Programming)面向切面编程,一种编程范式
- 作用:在不惊动原始设计的基础上为方法进行功能增强
- 核心概念
- 代理(Proxy):SpringAOP的核心本质是采用代理模式实现的
- 连接点(]oinPoint):在SpringAOP中,理解为任意方法的执行
- 切入点(Pointcut):匹配连接点的式子,也是具有共性功能的方法描述
- 通知(Advice):若干个方法的共性功能,在切入点处执行,最终体现为一个方法
- 切面(Aspect):描述通知与切入点的对应关系
- 目标对象(Target):被代理的原始对象成为目标对象
- 切入点
- 切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)
- execution( * com.itheima.service. * Service. * (…))
- 切入点表达式描述通配符:
- 作用:用于快速描述,范围描述
-
- :匹配任意符号(常用)
- …:匹配多个连续的任意符号(常用)
- +:匹配子类类型
- 切入点表达式书写技巧
- 1.按标准规范开发
- 2.查询操作的返回值建议使用 * 匹配
- 3.减少使用…的形式描述包
- 4.对接口进行描述,使用 * 表示模块名,例如JserService的匹配描述为 * Service
- 5.方法名书写保留动词,例如get,使用 * 表示名词,例如getById匹配描述为getBy *
- 6.参数根据实际情况灵活调整
- 切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)
- 通知类型
- 前置通知
- 后置通知
- 环绕通知(重点)
- 环绕通知依赖形参ProceedingJoinPoint(必须在第一位)才能实现对原始方法的调用
- 环绕通知可以隔离原始方法的调用执行(不调用pjp的原始方法)
- 环绕通知返回值设置为Object类型
- 环绕通知中可以对原始方法调用过程中出现的异常进行处理
- 返回后通知
- 抛出异常后通知
- 通知获取数据
- 获取切入点方法的参数
- JoinPoint:适用于前置、后置、返回后、抛出异常后通知,设置为方法的第一个形参
- Proceed]ointPoint:适用于环绕通知
- 获取切入点方法返回值
- 返回后通知
- 环绕通知
- 获取切入点方法运行异常信息
- 抛出异常后通知
- 环绕通知
- 获取切入点方法的参数
Spring事务
Spring事务简介
- 事务作用:在数据层保障一系列的数据库操作同成功同失败
- Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败
案例:银行账户转账
- 案例 模拟银行账户间转账业务
需求:实现任意两个账户间转账操作
需求微缩:A账户减钱,B账户加钱 - 分析:
①:数据层提供基础操作,指定账户减钱(outMoney),指定账户加钱(inMoney)
②:业务层提供转账操作(transfer),调用减钱与加钱的操作
③:提供2个账号和操作金额执行转账操作
④:基于Spring整合MyBatis环境搭建上述操作 - 结果分析:
①:程序正常执行时,账户金额A减B加,没有问题
②:程序出现异常后,转账失败,但是异常之前操作成功,异常之后操作失败,整体业务失败
- 注意事项
Springi注解式事务通常添加在业务层接口中而不会添加到业务层实现类中,降低耦合
注解式事务可以添加到业务方法上表示当前方法开启事务,也可以添加到接口上表示当前接口所有方法开启事务
- 注意事项
事务管理器要根据实现技术进行选择
MyBatis框架使用的是JDBc事务
- 注意事项
spring事务角色
- 事务角色
- 事务管理员:发起事务方,在Spring中通常指代业务层开启事务的方法
- 事务协调员:加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法
事务相关配置
案例:转账业务追加日志
- 案例 转账业务追加日志
需求:实现任意两个账户间转账操作,并对每次转账操作在数据库进行留痕
需求微缩:A账户减钱,B账户加钱,数据库记录日志 - 分析:
①:基于转账操作案例添加日志模块,实现数据库中记录日志
②:业务层转账操作(transfer),调用减钱、加钱与记录日志功能 - 实现效果预期:
无论转账操作是否成功,均进行转账操作的日志留痕 - 存在的问题
日志的记录与转账操作隶属同一个事务,同成功同失败
事务传播行为
- 事务传播行为:事务协调员对事务管理员所携带事务的处理态度