AOP-深入了解
AOP-深入了解
案例设定
- 需求: 测定接口的执行效率
- 简化: 在接口执行前输出当前系统时间
- 开发模式:
XML or 注解
思路分析
-
导入坐标
1
2
3
4
5
6
7
8
9
10
11
12
13<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
</dependencies> -
制作连接点方法
( 原始操作,Dao
)接口与实现类 1
2
3
4public interface BookDao {
void save();
void update();
}1
2
3
4
5
6
7
8
9
10
11
12
13
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("dao save...................");
}
public void update() {
System.out.println("dao update...................");
}
} -
制作共性功能
( 通知类与通知
) -
定义切入点
通配符含义 -
绑定切入点与通知关系
1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyAdvice {
/**
* @Before("execution(* com.example..*(..))")
* "*": 返回值类型
* com.example..*(..): com.example..【.. 表示com.example 包及其子包的路径】 *: 任意公共方法 (..【表示任意多个参数,】)
*/
public void showTime() {
System.out.println(System.currentTimeMillis());
}
} -
配置类
1
2
3
4
5
6
7
public class SpringConfig {
} -
启动测试
1
2
3
4
5
6
7public class Application {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao dao = ctx.getBean(BookDao.class);
dao.save();
}
}输出期望结果
AOP-工作流程
Spring
容器启动 - 读取所有切面配置中的切入点
- 初始化
bean
,判定bean
对应的类中的方法是否匹配到任意切入点 - 匹配失败,创建对象
- 匹配成功,创建原始对象
【目标对象】
的代理对象
- 获取
bean
执行方法 - 获取
bean
,调用方法并执行,完成操作 - 获取的
bean
是代理对象时, 根据代理对象的运行模式运行原始方法与增强的内容,完成操作
- 获取
概念
- 目标对象
( Target
): 原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的 - 代理
( Proxy
): 目标对象无法直接完成工作,需要对其进行功能回填, 通过原始对象的代理对象实现
AOP-切入点表达式
- 书写技巧
- 所有代码按照标准规范开发,
否则以下技巧全部实现 - 描述切入点
通常描述接口
,而不描述实现类 - 访问控制修饰符针对接口开发均采用
public
描述 ( 可省略访问控制修饰符描述
) - 返回值类型对于
增删改
类使用精准类型
加速匹配,对于查询类使用 *
统配快速描述 包名
书写尽量不使用
..
匹配,效率过低, 常用 *
做单个包描述匹配, 或精准匹配 接口名
书写名称与模块相关的/ 类名 采用 *
匹配,例如 UserService
书写成 *Service
,绑定业务层接口名 方法名
书写以动词
进行精准匹配
,名词采用 *
匹配, 例如 getById
书写成 getBy*,selectAll
书写成 selectAll
- 参数规则较为复杂,
根据业务方法灵活调整 - 通常
不使用异常
作为匹配规则
- 所有代码按照标准规范开发,
SpringBoot-AOP
-
目标
注解实现增强 -
实现思路
-
创建项目,
修改 pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies> -
创建
注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package com.example.aopboot.demo.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 修饰方法
// 作用范围
public Log {
}注解修饰的注解类会被 JavaDoc 工具提取成文档。 默认情况下,JavaDoc 是不包括注解的,但如果声明注解时指定了 ,就会被 JavaDoc 之类的工具处理,所以注解类型信息就会被包括在生成的帮助文档中。 是一个标记注解,没有成员变量。 用 -
创建
通知
类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class LogAdvice {
/**
* 定义切点:
*
* @annotation: 注解形式
* (com.example.aopboot.demo.annotation.Log)
*/
public void point() {
}
public void adviceWeb() {
System.out.println("load class file,place wait............................");
System.out.println(".");
System.out.println("...");
System.out.println("......");
System.out.println(".........");
System.out.println(".............");
System.out.println("load finish............................");
}
}区别 -
使用
1
2
3
4
5
6
7
8
9
10
11
12
13import com.example.aopboot.demo.annotation.Log;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
public class HelloWorld {
public String sayHello() {
return "say hello............";
}
}
-
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 coder-itl!
评论