SpringAOP 面向切面编程--准备工作

Posted 王六六的IT日常

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringAOP 面向切面编程--准备工作相关的知识,希望对你有一定的参考价值。

引言

1.创建一个SomeService接口类

public interface SomeService {
    void doSome();
    void doOther();
}

2.创建一个SomeService接口类的实现类SomeServiceImpl

选择对目录👇

public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome() {
        System.out.println("业务方法doSome(),计算商品购买金额");

    }

    @Override
    public void doOther() {
        System.out.println("业务方法doOther(),削减库存");

    }
}

3.测试类

public class MyTest {
    @Test
    public void test01(){
        SomeService service = new SomeServiceImpl();
        service.doSome();
        System.out.println("==============================");
        service.doOther();
    }
}


👇
4.增加日志时间功能

public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome() {
        //在业务方法开始时记录时间
        System.out.println("日志功能:记录方法的执行时间:" + new Date());
        System.out.println("业务方法doSome(),计算商品购买金额");
    }

    @Override
    public void doOther() {
        //在业务方法开始时记录时间
        System.out.println("日志功能:记录方法的执行时间:"+ new Date());
        System.out.println("业务方法doOther(),削减库存");
    }
}

测试:

5.添加事务提交功能

public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome() {

        //在业务方法开始时记录时间
        System.out.println("日志功能:记录方法的执行时间:" + new Date());

        System.out.println("业务方法doSome(),计算商品购买金额");

        //在业务方法之后,提交事务
        System.out.println("事务功能:提交事务处理");
    }
    
    @Override
    public void doOther() {
        //在业务方法开始时记录时间
        System.out.println("日志功能:记录方法的执行时间:"+ new Date());

        System.out.println("业务方法doOther(),削减库存");

        //在业务方法之后,提交事务
        System.out.println("事务功能:提交事务处理");
    }
}

测试:

增加功能,导致的问题:
每增加一个功能,源代码都要进行修改。上面例子中只有doSome和doOther两个,如果存在太多Service类,如果漏改一个功能会缺失。

业务方法功能重复太多、业务方法和非业务方法功能混合,难以管理和维护

在源代码中, 业务方法中增加的功能。
1)源代码可能改动的比较多。
2)重复代码比较多。
3)代码难于维护。

在不修改源代码👇的前提下,增加日志和事务功能

public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome() {
        System.out.println("业务方法doSome(),计算商品购买金额");
    }

    @Override
    public void doOther() {
        System.out.println("业务方法doOther(),削减库存");
    }
}

新建一个proxy👇

ServiceProxy.java实现SomeService,实现doSome、doOther业务方法

public class ServiceProxy implements SomeService{

    @Override
    public void doSome() {  
    }

    @Override
    public void doOther() {
    }
}



想用谁定义谁的对象,然后调用方法:

测试:

再加上日志功能:

再加上事务功能:

测试:

👇
原始业务功能(SomeServiceImpl)跟添加功能(ServiceProxy)分开了。
ServiceProxy在原始功能不变基础上还能实现增加删除功能。

  • 调用ServiceProxy类方法时候, 调用真正的目标方法,
  • 调用目标方法的时候,增加了一些功能。
  • ServiceProxy叫做代理, 代理对目标的操作。
  • 创建代理,可以完成对目标方法的调用, 增减功能。保持目标方法内容不变。

综上引出👇

AOP能实现代理所完成的功能

一、AOP 概念

AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编
程,可通过运行期动态代理实现程序功能的统一维护的一种技术。AOP 是Spring 框架中的一个重要内容。
利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

1. 什么是AOP

AOP(Aspect Orient Programming) : 面向切面编程
Aspect :表示切面, 给业务方法增加的功能,叫做切面。
切面一般都是非业务功能, 而且切面功能一般都是可以复用的。
例如: 日志功能, 事务功能, 权限检查,参数检查, 统计信息等等。
Orient:面向,对着
Programming:编程。

怎么理解面向切面编程 ?
以切面为核心设计开发你的应用
1)设计项目时, 找出切面的功能(日志、事务…)。
2)安排切面的执行时间, 执行的位置

2. AOP作用

1)让切面功能复用
2)让开发人员专注业务逻辑,提高开发效率
3)实现业务功能和其他非业务功能解耦合
4)给存在的业务方法增加功能,不用修改原来的代码

使用 AOP 减少重复代码,专注业务实现:

3. AOP编程术语(掌握)

  • Aspect:切面, 给业务方法增加的功能

  • JoinPoint:连接点(一个方法), 连接切面的业务方法。 在这个业务方法执行时,会同时执行切面的功能。– 上面例子中的doSome()

  • Pointcut: 切入点(多个方法), 是一个或多个连接点集合。 表示这些方法执行时,都能增加切面的功能。表示切面执行的位置。

  • target: 目标对象, 给哪个对象增加切面的功能, 这个对象就是目标对象。

  • Advice:通知(增强),表示切面的执行时间。 在目标方法之前执行切面,还是目标方法之后执行切面。通知定义了增强代码切入到目标代码的时间点

切入点定义切入的位置,通知定义切入的时间。

AOP中重要的三个要素: Aspect, Pointcut , Advice。

👇👇👇👇👇👇
这三个概念的理解是: 在Advice的时间,在Pointcut的位置, 执行Aspect。

AOP是一个动态的思想。
在程序运行期间,创建代理(上面例子中的ServcieProxy),使用代理执行方法时,增加切面的功能。
这个代理对象是存在内存中的。

4. 什么时候你想用AOP

  • 要给某些方法增加相同的一些功能
  • 源代码不能改
  • 给业务方法增加非业务功能

5. AOP技术思想的实现

使用框架实现AOP。
实现AOP的框架有很多----有名的两个👇

  • Spring : Spring框架实现AOP思想中的部分功能。 Spring框架实现AOP的操作比较繁琐,比重。👉后面会提到事务中 👉使用Spring事务注解管理事务 👉Spring使用自己的AOP
  • Aspectj : 独立的框架,专门做AOP, 属于Eclipse

6. AspectJ 对 AOP 的实现 (掌握)

AspectJ 简介:
对于 AOP 这种编程思想,很多框架都进行了实现。Spring 就是其中之一,可以完成面向切面编程。然而,AspectJ 也实现了 AOP 的功能,且其实现方式更为简捷,使用更为方便,而且还支持注解式开发。所以Spring 又将AspectJ 的对于 AOP 的实现也引入到了自己的框架中

在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式。

AspectJ 是一个优秀面向切面的框架,它扩展了 Java 语言,提供了强大的切面实现。👉 官网地址
AspetJ 是 Eclipse 的开源项目,官网介绍如下:

AspectJ框架可以使用注解XML配置文件两种方式实现 AOP。

6.1 通知

Aspectj 用通知(Advice)表示切面执行时间。
这个通知可以使用注解表示。
5个注解表示切面的5个执行时间, 这些注解叫做通知注解

  • @Before :前置通知
  • @AfterRetunring:后置通知
  • @Around::环绕通知
  • @AfterThrowing:异常通知
  • @After:最终通知

6.2 Pointcut 位置

Pointcut 用来表示切面执行的位置, 使用Aspectj中切入点表达式。

AspectJ 定义了专门的表达式用于指定切入点。
表达式的原型是:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
 // ?表示可选的部分 可以省略

👆从Spring文档中找到

切入点表达式(共 4 个部分)语法:

execution(访问权限 方法返回值 方法声明(参数) 异常类型)

带 ?的部分可以省略

相当于完整的方法定义:

execution(public void com.bjpowernode.proxy.ServiceProxy.doSome(String))

//简单版:
execution( void doSome(String))

execution(访问权限 方法返回值 方法声明(参数) 异常类型)
红色部分必须出现,表达式中黑色文字表示可省略部分,各部分间用空格分开。在其中可以使用以下符号:
通配符

符号意义
*0至多个任意字符
用在方法参数中
+用在类名后,表示当前类及其子类
+用在接口后,表示当前接口及其实现类

举例:
1.execution(public * *(..)) 指定切入点为:任意公共方法。


2.execution(* set*(..)) 指定切入点为:任何一个以“set”开始的方法。

3.execution(* com.xyz.service.*.*(..)) 指定切入点为:定义在 service 包里的任意类任意方法


4.execution(* com.xyz.service..*.*(..)) 指定切入点为:定义在service 包或者子包 里的任意类任意方法。“…”出现在类名中时,后面必须跟“*”,表示包、子包下的所有类。

5.execution(* *..service.*.*(..)) 指定所有包下的 serivce 子包下所有类(接口)中所有方法为切入点


以上是关于SpringAOP 面向切面编程--准备工作的主要内容,如果未能解决你的问题,请参考以下文章

SpringAOP面向切面编程

springAOP之代理模式

图文并茂!!!一文搞懂SpringAOP(面向切面编程)

图文并茂!!!一文搞懂SpringAOP(面向切面编程)

SpringAOPAOP面向切面编程

SpringAOP