Blog

  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

SpringAop

发表于 2019-08-09 分类于 Spring 阅读次数:
本文字数: 5.2k

简介

面向方面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP)。OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面。方面实现了跨越多种类型和对象的关注点(例如事务管理)的模块化。(这些担忧在AOP文献中通常被称为“横切”问题。)

概念和术语

  • Aspect(切面):横切关注点被模块化的特殊对象。即,它是一个类
  • Join point(连接点):程序执行期间的一个点,例如执行方法或处理异常。在Spring AOP中,连接点始终表示方法执行。
  • Advice(通知):切面必须要完成的工作。即,它是类中的一个方法。
  • Pointcut(切点):由切入点表达式匹配的连接点(就是符合表达式的连接点的集合)
  • Introduction(引入):Spring AOP允许您向任何建议的对象引入新接口(以及相应的实现),就是在给类添加接口。
  • Target object(目标对象):被通知对象。
  • AOP proxy(AOP代理):在ioc容器初始化时,将目标对象变成代理对象
  • Weaving(织入)

通知类型

  • Before advice(@Before):在连接点之前运行,但无法阻止执行流程进入连接点(除非它抛出异常)
  • After returning advice (@AfterReturn):在连接点正常完成后运行(如果方法返回而不抛出异常)
  • After throwing advice (@AfterThrowing):如果方法通过抛出异常退出
  • After(@After):无论连接点退出的方式(正常或异常返回),都要执行建议
  • Around(@Around): around通知可以在方法调用之前和之后执行自定义行为,它还负责选择是继续连接点还是通过返回自己的返回值或抛出异常来快速建议的方法执行。

* 由于Spring AOP(如AspectJ)提供了全方位的建议类型,因此我们建议您使用可以实现所需行为的最不强大的建议类型 (应该就是能用Before或者After的就尽量别用Around叭,不强大的能解决,何必要用强大的呢~,应该是这样子叭)

基本使用

启用@AspectJ支持

1
2
3
4
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}

声明一个切面(里面包含切点,通知)

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@Component
@Aspect
public class AspectOne {
//这是一个切点
//Spring AOP支持AspectJ切入点指示符(PCD)用于切入点表达式:除了execution,还有within、this等,详情参加官方文档
//切点里面的匹配的就是连接点。
@Pointcut("execution(public * *(..))")
private void PointCutOne() {
}
//以下都是各种类型的通知
@Before("PointCutOne() && args(test)") //匹配连接点中,有test参数的连接点
public void Before(String test) {
System.out.println("before .......");
System.out.println("test:"+test);
}

@After("PointCutOne()")
public void After() {
System.out.println("After .......");
}

@AfterThrowing("PointCutOne()")
public void AfterThrowing() {
System.out.println("AfterThrowing......");
}

//获取异常对象
@AfterThrowing(
pointcut = "PointCutOne()",
throwing = "ex"
)
public void AfterThrowing(RuntimeException ex) {
System.out.println("AfterThrowing:" + ex.getMessage());
}

@AfterReturning("PointCutOne()")
public void AfterReturning() {
System.out.println("AfterReturning......");
}

@Around("PointCutOne()")
public void Around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("Around......");
//Class<?> aClass = pjp.getTarget().getClass();
Object proceed = pjp.proceed();
System.out.println(proceed);
}
}

通知参数(参数也可以放在PointCut中)

  • 如果第一个参数是的JoinPoint,ProceedingJoinPoint,JoinPoint.StaticPart类型,可以直接写,JoinPoint接口有许多方法:
    • getTarget() getTarget():返回目标对象。
    • getArgs():返回方法参数。
    • getSignature():返回正在通知的方法的描述。
    • toString():打印通知方法的有用说明。
    • getThis():返回代理对象。
  • ProceedingJoinPoint参数只能写在Around通知中
1
2
3
4
5
@Before("PointCutOne() && args(test)")
public void Before(JoinPoint jp, String test) {
System.out.println("before .......");
System.out.println("test:"+test);
}

通知顺序

当多条建议都想在同一个连接点运行时会发生什么?还没去了解。哈哈哈哈哈哈

测试类

1
2
3
4
5
6
7
8
9
10
11
public class Application {
public static void main(String[] args) {
//创建ioc容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.yb");
//从容器中获取
SpringAopTest springaoptest = (SpringAopTest) context.getBean(SpringAopTest.class);
//Object springAopTest = context.getBean("springAopTest");
springaoptest.test1("hello world");
springaoptest.test2();
}
}
1
2
3
4
5
6
7
8
9
10
11
@Component
public class SpringAopTest {
public String test1(String test){
System.out.println("test1......");
return "test1";
}
public void test2() throws RuntimeException{
System.out.println("test2......");
throw new RuntimeException("test2 exception");
}
}

结果(around和其他的分开调试)

1
2
3
4
5
6
7
8
9
10
before .......
test:hello world
test1......
After .......
AfterReturning......

test2......
After .......
AfterThrowing......
AfterThrowing:test2 exception

引入(Introductions)

前面描述的几种增强(Advice)都是在目标方法范围内织入,而引介(Introduction)不同,直接在类级别上添加目标未实现的接口方法。
根据官方文档的介绍:您可以使用@DeclareParents注解进行介绍。此注解用于声明匹配类型具有新父级

声明一个接口,和一个实现类

1
2
3
public interface SayHello {
void SayHello();
}
1
2
3
4
5
6
public class SayHelloImpl implements SayHello {
@Override
public void SayHello() {
System.out.println("hello");
}
}

在切面中使用@DeclareParents注解对特定的类进行引入新方法

1
2
@DeclareParents(value = "com.yb.test.*",defaultImpl = SayHelloImpl.class)
public static SayHello sayHello;

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.yb");
SpringAopTest springaoptest = (SpringAopTest) context.getBean(SpringAopTest.class);
//方式一:获取springaoptest对象中的所有接口,查看是否存在新增的接口
Class<?>[] interfaces = springaoptest.getClass().getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println(anInterface.getName());
}
//方式二:强转一下,看看是否成功
SayHello springaoptest2 = (SayHello)springaoptest;
springaoptest2.SayHello();
}
}

结果

1
2
3
4
5
6
com.yb.myinterface.SayHello
org.springframework.aop.SpringProxy
org.springframework.aop.framework.Advised
org.springframework.cglib.proxy.Factory

hello

说明这个对象确实实现了接口 (就是不知道有啥用处。。。感觉直接实现接口不是差不多嘛)

官方文档

------ 已触及底线感谢您的阅读 ------
麻辣香锅不要辣 微信支付

微信支付

  • 本文作者: 麻辣香锅不要辣
  • 本文链接: https://http://ybhub.gitee.io/2019/08/09/SpringAop/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
# SpringAop
Servlet
SpringAop------代理对象的创建(一)
  • 文章目录
  • 站点概览
麻辣香锅不要辣

麻辣香锅不要辣

21 日志
11 分类
20 标签
GitHub 简书
  1. 1. 简介
  2. 2. 概念和术语
  3. 3. 通知类型
  4. 4. 基本使用
    1. 4.1. 启用@AspectJ支持
    2. 4.2. 声明一个切面(里面包含切点,通知)
      1. 4.2.1. 通知参数(参数也可以放在PointCut中)
      2. 4.2.2. 通知顺序
    3. 4.3. 测试类
    4. 4.4. 结果(around和其他的分开调试)
  5. 5. 引入(Introductions)
    1. 5.1. 声明一个接口,和一个实现类
    2. 5.2. 在切面中使用@DeclareParents注解对特定的类进行引入新方法
    3. 5.3. 测试
    4. 5.4. 结果
© 2019 – 2020 麻辣香锅不要辣 | 站点总字数: 20.4k字
|
0%