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 面向切面编程--准备工作的主要内容,如果未能解决你的问题,请参考以下文章