Spring
IOC:容器 管理对象(创建对象、管理对象的生命周期)
DI:对象属性值的注入
AOP:面向切面管理
AOP场景
1、日志切面
2、事务切面
@Transactional
设置自动提交模式关闭
开启事务
dml;
commit;||rollback
3、权限切面 springsecurity
@RequirePermission()
//校验权限
public void login(){}
//校验权限(是否登录成功)
//是否是管理员
//查询账户
4、自定义切面(自定义业务逻辑)
AOP的由来
package a{
@Slf4j
class A{
void m1(){
log.info("A...m1...start"+new Date());
try{
//业务功能
}catch(Exception e){
log.error("异常信息.....");
}
log.info("A...m1...end"+new Date());
}
void m2(){
log.info("A...m2...start"+new Date());
//业务功能
log.info("A...m2...end"+new Date());
}
}
@Slf4j
class B{
void m1(){
log.info("B...m1...start"+new Date());
//业务功能
log.info("B...m1...start"+new Date());
}
void m2(){
//业务功能
}
}
}
AOP: 将与主业务无关的辅助业务逻辑,提取出来,形成aop切面,然后动态的切入到任务需要的位置。
切面类
@Aspect
@Component
class MyLog{
//切入点
@PointCut("表达式")
public void pt(){}
@Before
public void before(){}
@After
public void after(){}
@Exception
public void exception(){}
}
自定义日志切面
1、目标类、目标方法
package com.hl.springboot4.web;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/*
目标类
*/
@RestController
@RequestMapping("/user")
public class UserController {
//目标方法
@RequestMapping("/m1")
public void m1(){
System.out.println(1/0);
System.out.println("m1..........");
}
//目标方法
@RequestMapping("/m2")
public void m2(){
System.out.println("m2..........");
}
}
2、切面类、切面方法
<!-- 切面织入的jar包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
/*
切面类
*/
@Aspect //将当前类标记为切面类
@Component
public class MyLog {
public void before(){
System.out.println("before method...");
}
public void after(){
System.out.println("after method...");
}
}
3、定义切入点和通知
/*
切面类
*/
@Aspect //将当前类标记为切面类
@Component
public class MyLog {
/*
切入点 :通过切入点,定位到具体的目标类、目标方法
execution(* com.hl.springboot4.web.UserController.*(..))
第一个*代表方法的返回值类型
第二个*代表方法名
(..) 代表方法任意形参
*/
@Pointcut(value = "execution(* com.hl.springboot4.web.UserController.*(..))")
//@Pointcut(value = "execution(* com.hl.springboot4..*.*(..))")
public void pt(){}
//切面方法
/*
通知 : 切面方法在目标方法上执行的时机
前置通知:
后置通知:
after :目标方法是否异常,都要执行
afterReturning:目标方法成功返回后执行
异常通知:
环绕通知:
*/
@Before("pt()")
public void before(){
System.out.println("before method...");
}
@After("pt()")
public void after(){
System.out.println("after method...");
}
@AfterReturning(value = "pt()",returning = "obj")
public void afterReturning(Object obj){
System.out.println(obj);
System.out.println("after returning...");
}
@AfterThrowing(value = "pt()",throwing = "e")
public void afterThrowing(Throwable e){
System.out.println("after throwing...");
}
/*
环绕通知=前置通知+后置通知
*/
@Around("pt()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
//前置通知
System.out.println("around ..... before");
//调用目标方法
joinPoint.proceed();
//后置通知
System.out.println("around ..... after");
}
}
4、测试
AOP名词
aspect 面向切面编程语言 方法 方法参数 初始化
spring----针对 aspect的实现,实现了其中的部分功能
连接点一定是切入点,但是切入点不一定是连接点。
名称 | |
---|---|
Joinpoint(连接点) | 连接点则指可以被动态代理拦截目标类的方法。 |
Pointcut(切入点) | 又称切点,指要对哪些 Joinpoint 进行拦截,即连接点的选择器。 |
Advice(通知) | 指拦截到 Joinpoint 之后要执行的代码,即对切入点增强的内容。又称为增强。 |
Target(目标) | 指代理的目标对象,通常也被称为被通知(advised)对象。 |
Weaving(织入) | 指把增强代码应用到目标对象上,生成代理对象的过程。 |
Proxy(代理) | 指生成的代理对象。 |
Aspect(切面) | 通知和切入点共同组成了切面。 |
通知类型:
通知 | 说明 |
---|---|
before(前置通知) | 通知方法在目标方法调用之前执行 |
after(后置通知) | 通知方法在目标方法返回或异常后调用 |
after-returning(返回后通知) | 通知方法会在目标方法返回后调用 |
after-throwing(抛出异常通知) | 通知方法会在目标方法抛出异常后调用 |
around(环绕通知) | 通知方法会将目标方法封装起来 |
代理类
class Target{
void m1(){}
}
class Aspect{
before(){}
}
//代理类
class TargetProxy{
aspect.before()
target.m1()
aspect.after()
}
代理模式
1、静态代理
提前在项目中创建好的代理类
//代理类
class TargetProxy{
aspect.before()
target.m1()
aspect.after()
}
2、动态代理
在项目运行过程中,动态创建的代理类
$Proxy = Proxy.create(Target,Aspect);
jdk代理模式:针对接口的代理,要求被代理的类必须实现接口
cglib代理:针对类的代理
spring整合jdbc实现事务操作
1、jar包准备
<!-- mysql-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!--springboot-jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
2、配置文件
server:
port: 8080
#数据库连接
spring:
datasource:
url: jdbc:mysql://localhost:3306/yan9
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
3、数据库表
create table account(
id int primary key auto_increment,
name char(16),
money double
);
insert into account(name,money) values ('张三',10000),('李四',2000);
4、pojo
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Account {
private int id;
private String name;
private Double money;
}
5、web层、service层、dao层
@RestController
public class AccountController {
@Autowired
private AccountService accountService;
@RequestMapping("/transfer")
public Object transfer(Integer fromId, Integer toId, Double money){
//接收数据,传递数据到业务层
boolean flag = accountService.transfer(fromId, toId, money);
//返回结果给客户端
return flag;
}
}
public interface AccountService {
public boolean transfer(Integer fromId, Integer toId, double money);
}
@Service
@Transactional
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountDao accountDao;
@Override
// @Transactional//事务注解
public boolean transfer(Integer fromId, Integer toId, double money) {
//转出方法
int num1 = accountDao.transferOut(fromId,money);
System.out.println(1/0);
//转入方法
int num2 = accountDao.transferIn(toId,money);
return num1==num2&&num1>0 ? true : false;
}
}
public interface AccountDao {
//转出
public int transferOut(Integer fromId,Double money);
//转入
public int transferIn(Integer toId,Double money);
}
package com.hl.springboot4.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.RequestMapping;
@Repository
public class AccountDaoImpl implements AccountDao{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int transferOut(Integer fromId, Double money) {
String sql = "update account set money = money - ? where id = ?";
return jdbcTemplate.update(sql, money, fromId);
}
@Override
public int transferIn(Integer toId, Double money) {
String sql = "update account set money = money + ? where id = ?";
return jdbcTemplate.update(sql, money, toId);
}
}
@Transactional
@EnableTransactionManagement 开启全局事务支持
@Transactional 使用事务
readOnly = true, 只读事务 当前事务中查询出的数据,不能用户更新操作
rollbackFor = Exception.class 当遇到特定异常,执行rollback回滚
noRollbackFor = {} 当发生某种异常,不回滚
timeout=数值 超时时间
propagation = 事务的传播机制 a--调用-->b b是否能够使用事务的问题
Propagation.REQUIRED
isolation = 事务的隔离行为 两个方法在使用事务时,对方操作的数据是否可见
事务的传播行为
事务传播描述的事务与事务之间的传播关系, 常见的场景是在一个嵌套调用的方法中,外部方法和内部每个方法都添加了事务管理, 不同的传播行为配置,决定了最终是这些方法是使用同一个事务,还是在不同的事务中运行。
PROPAGATION_REQUIRED (默认)
支持当前事务,如果当前已经存在事务,就加入到事务中执行,如果当前没有事务,就新建一个事务。这是最常见的选择。
public class Demo{
void a(){
b();//新建事务
}
@Transactional
void a(){
b(); //使用a的事务
}
@Transactional
void b();
}
PROPAGATION_SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行。
public class Demo{
void a(){
b();//不要事务
}
@Transactional
void a(){
b(); //使用a的事务
}
@Transactional
void b();
}
PROPAGATION_MANDATORY
支持当前事务,如果当前没有事务,就抛出异常。
public class Demo{
void a(){
b();//报错
}
@Transactional
void a(){
b(); //使用a的事务
}
@Transactional
void b();
}
PROPAGATION_REQUIRES_NEW
新建事务,如果当前存在事务,把当前事务挂起。
public class Demo{
void a(){
b();//新建
}
@Transactional
void a(){
b(); //挂起a事务 新建事务
}
@Transactional
void b();
}
PROPAGATION_NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
public class Demo{
void a(){
b();
}
@Transactional
void a(){
b(); //挂起a事务
}
@Transactional
void b();
}
PROPAGATION_NEVER
以非事务方式执行,如果当前存在事务,则抛出异常。
public class Demo{
void a(){
b();
}
@Transactional
void a(){
b(); //报错
}
@Transactional(传播级别)
void b();
}
PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
嵌套事务: 与REQUIRED不同, NESTED支持真正意义上的子事务, 父事务回滚会将所有子事务都回滚,子事务回滚不会引起父事务的回滚。而REQUIRED其实只有一个物理事务。
public class Demo{
void a(){
b(); //新建
}
@Transactional 父事务
void a(){
b(); // 新建事务 子事务
}
@Transactional(传播级别)
void b();
}
总结
1、aop切面相关的名词(掌握)
2、如何实现自定义切面(掌握)
3、事务的四个特性
4、如何使用事务@Transactional
5、事务的传播机制
6、springboot整合jdbc过程
7、文件上传、下载功能如何实现
8、aop使用场景