AOP

115 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

Spring整合MyBatis

image.png

image.png mybatis管理sqlSessionFactory对象

spring整合junit

//设置类运行器
@RunWith(SpringJUnit4ClassRunner.class)
//设置Spring环境对应的配置类
@ContextConfiguration(classes = SpringConfig.class)
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());
    }


}

image.png

AOP简介

AOP:面向切面编程,一种编程范式,指导开发者如何组织程序架构

作用:在不惊动原始设计的基础上为其进行功能增强

Spring理念:无入侵式/无侵入式

image.png

AOP入门案例分析

案例:在接口执行前输出当前系统时间

开发模式:xml or 注解

思路分析:

1.导入坐标(pop.xml)

image.png 2.制作连接点方法(原始操作,Dao接口和实现类)

image.png 3.制作共性功能(通知类与通知)

image.png

4.定义切入点

image.png 5.绑定切入点与通知关系-->切面

image.png PS:在通知类前加上

image.png 在配置类前加入

image.png

AOP工作流程❤️

核心本质:代理模式

1.spring容器启动

2.读取所有切面配置中的切入点

3.初始化bean,判定bean对应的类中的方法是否匹配到任意切入点

  • 匹配失败,创建对象
  • 匹配成功,创建原始对象(目标对象)的代理对象

4.获取bean执行方法

  • 获取bean,调用方法并执行,完成操作
  • 获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作

核心概念

目标对象(Target )︰原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的

代理( Proxy ) ︰目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现

AOP切入点表达式

切入点:要进行增强的方法

切入点表达式:要进行增强的方法的描述方式

image.png

切入点表达式标准格式︰

动作关键字(访问修饰符 返回值﹑包名.类/接口名.方法名(参数)异常名)

image.png

image.png

image.png

AOP通知类型

image.png

image.png

@Pointcut("execution(void com.itheima.dao.BookDao.update())")
    private void pt(){}
    @Pointcut("execution(int com.itheima.dao.BookDao.select())")
    private void pt2(){}

    //@Before:前置通知,在原始方法运行之前执行
//    @Before("pt()")
    public void before() {
        System.out.println("before advice ...");
    }

    //@After:后置通知,在原始方法运行之后执行
//    @After("pt2()")
    public void after() {
        System.out.println("after advice ...");
    }

    //@Around:环绕通知,在原始方法运行的前后执行
//    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before advice ...");
        //表示对原始操作的调用
        Object ret = pjp.proceed();
        System.out.println("around after advice ...");
        return ret;
    }

//    @Around("pt2()")
    public Object aroundSelect(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before advice ...");
        //表示对原始操作的调用
        Integer ret = (Integer) pjp.proceed();

        System.out.println("around after advice ...");
        return ret;
    }

    //@AfterReturning:返回后通知,在原始方法执行完毕后运行,且原始方法执行过程中未出现异常现象
//    @AfterReturning("pt2()")
    public void afterReturning() {
        System.out.println("afterReturning advice ...");
    }

    //@AfterThrowing:抛出异常后通知,在原始方法执行过程中出现异常后运行
    @AfterThrowing("pt2()")
    public void afterThrowing() {
        System.out.println("afterThrowing advice ...");
    }
}

image.png

image.png

image.png

AOP通知获取数据

image.png

@Pointcut("execution(* com.itheima.dao.BookDao.findName(..))")
    private void pt(){}

    //JoinPoint:用于描述切入点的对象,必须配置成通知方法中的第一个参数,可用于获取原始方法调用的参数
    @Before("pt()")
    public void before(JoinPoint jp) {
        Object[] args = jp.getArgs();
        System.out.println(Arrays.toString(args));
        System.out.println("before advice ..." );
    }

    //@After("pt()")
    public void after(JoinPoint jp) {
        Object[] args = jp.getArgs();
        System.out.println(Arrays.toString(args));
        System.out.println("after advice ...");
    }

    //ProceedingJoinPoint:专用于环绕通知,是JoinPoint子类,可以实现对原始方法的调用
    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) {
        Object[] args = pjp.getArgs();
        System.out.println(Arrays.toString(args));
        args[0] = 666;
        Object ret = null;
        try {
            ret = pjp.proceed(args);
        } catch (Throwable t) {
            t.printStackTrace();
        }
        return ret;
    }

    //设置返回后通知获取原始方法的返回值,要求returning属性值必须与方法形参名相同
    //@AfterReturning(value = "pt()",returning = "ret")
    public void afterReturning(JoinPoint jp,String ret) {
        System.out.println("afterReturning advice ..."+ret);
    }

    //设置抛出异常后通知获取原始方法运行时抛出的异常对象,要求throwing属性值必须与方法形参名相同
    //@AfterThrowing(value = "pt()",throwing = "t")
    public void afterThrowing(Throwable t) {
        System.out.println("afterThrowing advice ..."+t);
    }
}

说明:对于around,使用ProceedingJoinPoint pjp

对于其他4个,使用JoinPoint jp

案例:百度网盘密码数据兼容处理

image.png

image.png

AOP总结

image.png

image.png

image.png

image.png

Spring事务简介

案例:银行账户转账

事务作用:在数据层保障一系列的数据库操作同成功同失败

Spring事务作用:在数据库或业务层保障一系列的数据库操作同成功同失败

image.png

image.png

image.png 在类或接口上使用@Transactional可以使该类或接口中的所有方法都添加事务管理

image.png 3:开启注解式事务驱动

image.png

Spring事务角色

事务管理员

发起事务方,在Spring中通常指代业务层开启事务的方法

事务协调员

加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法

image.png

事务相关配置

image.png

转账业务追加日志

需求:实现任意两个账户间转账操作,并对每次转账操作在数据库进行留痕

需求微缩:A账户加钱,B账户减钱,数据库记录日志

image.png 1.

image.png

image.png