AOP面向切面编程

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

底层实现

Spring 的 AOP 的底层用到两种代理机制:

  • JDK 的动态代理 :类必须实现接口,所以是针对实现了接口的类产生代理.
  • Cglib 的动态代理:针对没有实现接口的类产生代理,应用的是底层的字节码增强的技术生成当前类的子类对象

JDK 的动态代理

  • UserService接口,实现增删改查的功能
1
2
3
4
5
6
7
8
package com.cuzz.service;public interface UserService {void add();void delete();void update();void get();
}
  • UserService接口的实现的类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class UserServiceImpl implements UserService {@Overridepublic void add() {System.out.println("添加一个user");}@Overridepublic void delete() {System.out.println("删除一个user");}@Overridepublic void update() {System.out.println("更新一个user");}@Overridepublic void get() {System.out.println("查询一个user");}
}
  • 实现动态代理
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
package com.cuzz.service;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class UserServiceProxyFactory implements InvocationHandler{private UserService us;public UserServiceProxyFactory(UserService us) {super();this.us = us;}// 获得动态代理public UserService getUserServiceProxy() {// 生成动态代理UserService usProxy = (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),UserServiceImpl.class.getInterfaces(), this); // 这个 this 就是实现 InvocationHandler 的对象return usProxy;}@Overridepublic Object invoke(Object arg0, Method method, Object[] arg2)throws Throwable {System.out.println("打开事务!");Object invoke = method.invoke(us, arg2);System.out.println("提交事务!");return invoke;}
}
  • 测试
1
2
3
4
5
6
7
8
9
public class TestDemo {    @Testpublic void test01(){UserService us = new UserServiceImpl();       UserServiceProxyFactory factory = new UserServiceProxyFactory(us);        UserService usProxy = factory.getUserServiceProxy();     usProxy.add();   }
}
  • 输出
1
2
3
打开事务!
添加一个user
提交事务!

Cglib 的动态代理

  • Cglib 的动态代理的代码实现
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
package com.cuzz.service;import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;public class UserServiceProxyFactory2 implements MethodInterceptor {public UserService getUserServiceProxy(){// 帮我们生成代理对象Enhancer en = new Enhancer();// 设置对谁进行代理en.setSuperclass(UserServiceImpl.class);// 代理要做什么en.setCallback(this);// 创建代理对象UserService us = (UserService) en.create();return us;}@Overridepublic Object intercept(Object prxoyobj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {// 打开事务System.out.println("打开事务!");// 调用原有方法Object returnValue = methodProxy.invokeSuper(prxoyobj, arg);// 提交事务System.out.println("提交事务!");return returnValue;}
}
  • 测试
1
2
3
4
5
6
@Test
public void test02() {    UserServiceProxyFactory2 factory = new UserServiceProxyFactory2();  UserService usProxy = factory.getUserServiceProxy();usProxy.add();
}

Spring的AOP开发(基于AspectJ)

AOP的开发中的相关术语:

  • Joinpoint(连接点):所谓连接点是指那些被拦截到的点,在 spring 中这些点指的是方法,因为 spring 只支持方法类型的连接点
  • Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
  • Advice(通知/增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
  • Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field
  • Target(目标对象):代理的目标对象
  • Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程,spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装在期织入
  • Proxy(代理):一个类被 AOP 织入增强后,就产生一个结果代理类
  • Aspect(切面):是切入点和通知(引介)的结合

通知类型

  • 前置通知 :在目标方法执行之前执行
  • 后置通知 :在目标方法执行之后执行
  • 环绕通知 :在目标方法执行前和执行后执行
  • 异常抛出通知:在目标方法执行出现异常的时候执行
  • 最终通知 :无论目标方法是否出现异常 最终通知都会执行

代码演示

通知类,给切面的目标方法标注何时地运行,必须告诉 Spring 哪个类是切面类,添加注解 @Aspect

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
@Aspect  // 表示该类是一个通知类
public class MyAdvice {// 前置通知@Before("execution(* com.cuzz.service..*ServiceImpl.*(..))")public void before(){System.out.println("这是前置通知!!");}// 后置通知@AfterReturning("execution(* com.cuzz.service..*ServiceImpl.*(..))")public void afterReturning(){System.out.println("这是后置通知(如果出现异常不会调用)!!");}// 环绕通知@Around("execution(* com.cuzz.service..*ServiceImpl.*(..))")public Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("这是环绕通知之前的部分!!");// 调用目标方法Object proceed = pjp.proceed();System.out.println("这是环绕通知之后的部分!!");return proceed;}// 异常通知@AfterThrowing("execution(* com.cuzz.service..*ServiceImpl.*(..))")public void afterException(){System.out.println("出事啦!出现异常了!!");}// 后置通知@After("execution(* com.cuzz.service..*ServiceImpl.*(..))")public void after(){System.out.println("这是后置通知(出现异常也会调用)!!");}
}

配置类,将切面类和业务逻辑类都加入到容器中,给配置类加 @EnableAspectJAutoProxy 注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*** @Author: cuzz* @Date: 2019/2/10 20:43* @Description:*/
@Configuration
@EnableAspectJAutoProxy
public class MainConfigOfAOP {@Beanpublic UserService userService() {return new UserServiceImpl();}@Beanpublic MyAdvice myAdvice() {return new MyAdvice();}
}

测试

1
2
3
4
5
6
7
8
9
10
@Test
public void test03() {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);UserService userService = (UserService) applicationContext.getBean("userService");userService.add();userService.delete();userService.update();userService.get();
}

如果报错添加依赖

1
2
3
4
5
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.4</version></dependency>

Spring注解驱动开发(四)相关推荐

  1. Spring注解驱动开发学习总结8:自动装配注解@Autowire、@Resource、@Inject

    Spring注解驱动开发学习总结8:自动装配注解@Autowire.@Resource.@Inject 1.自动装配@Autowire.@Resource.@Inject 1.1 构建bookDao ...

  2. 0、Spring 注解驱动开发

    0.Spring注解驱动开发 0.1 简介 <Spring注解驱动开发>是一套帮助我们深入了解Spring原理机制的教程: 现今SpringBoot.SpringCloud技术非常火热,作 ...

  3. Spring注解驱动开发第26讲——总有人让我给他讲讲@EnableAspectJAutoProxy注解

    @EnableAspectJAutoProxy注解 在配置类上添加@EnableAspectJAutoProxy注解,便能够开启注解版的AOP功能.也就是说,如果要使注解版的AOP功能起作用的话,那么 ...

  4. 【Spring注解驱动开发】二狗子让我给他讲讲@EnableAspectJAutoProxy注解

    写在前面 最近,二狗子入职了新公司,新入职的那几天确实有点飘.不过慢慢的,他发现他身边的人各个身怀绝技啊,有Spring源码的贡献者,有Dubbo源码的贡献者,有MyBatis源码的贡献者,还有研究A ...

  5. SPRING注解驱动开发-雷神课程超详细笔记

    SPRING注解驱动开发-雷神课程超详细笔记 时间:2021-03-21 2022-04-06更新:最近翻起一年多前写的笔记复习,还是收获颇多,很多当时无法理解的知识现在慢慢能理解了,可能是工作一年的 ...

  6. spring注解驱动开发-5 Spring AOP实现

    Spring AOP实现 前言 AOP案例实现 1.编写目标类 2.编写切面类 3.编写配置类 4.编写测试类 end... 前言 AOP为Aspect Oriented Programming的缩写 ...

  7. spring注解驱动开发-10 Servlet3.0

    Spring AOP实现 前言 servlet3.0简介 ServletContainerInitializer shared libraries(共享库) / runtimes pluggabili ...

  8. spring注解驱动开发-8 Spring 扩展原理

    Spring 扩展原理 前言 BeanFactoryPostProcessor 测试实例编写 ExtConfig MyBeanFactoryPostProcessor ExtTest 源码分析 Bea ...

  9. spring注解驱动开发-4 Spring 自动装配

    Spring 自动装配 前言 Spring 自动装配的几种方式 1.@Autowired @Qualifier("组件id") @Primary 2.@Resource方式 3.@ ...

  10. spring注解驱动开发-7 Spring声明式事务

    Spring 声明式事务 前言 @EnableTransactionManagement AutoProxyRegistrar InfrastructureAdvisorAutoProxyCreato ...

最新文章

  1. 计算机网络分为两大阶段,【多选题】计算机网络的发展分为哪些阶段?() A. 远程终端联机阶段 B. 计算机网络阶段 C. 计算机网络互联阶段 D. 信息高速公路阶段...
  2. 2019最新实战!给程序员的7节深度学习必修课,最好还会Python!
  3. ICRA2022 | OPV2V: 首个大型自动驾驶协同感知数据集+代码框架已开源
  4. java String format占位符
  5. 中国计算机学会CCF推荐国际学术会议和期刊目录-软件工程/系统软件/程序设计语言
  6. 使用代码获得所有适用于创建的transaction type
  7. linux 分卷压缩到指定目录,运用在android下Linux分卷压缩与分卷解压的命令
  8. java mysubmail_关于MyBatis10种超好用的写法(收藏)
  9. JDK1.5提供的原子类原理及使用
  10. GitHub#SQL#:SQL必知必会
  11. 上岸 1 年后,重回大厂内卷
  12. 午夜时分的51CTO博客与白天有什么不同?
  13. 超好用的数学教学软件:几何画板Sketchpad for Mac中文版
  14. 第三方开发工具—PyCharm(安装、使用、汉化)超详细、图超多、注脚特多(Windows操作系统)
  15. Windows 10家庭版也能共享打印机(上)启用Guest账户
  16. 2017关于自学PHP的方法
  17. Eth-Trunk(链路聚合)之负载分担模式
  18. 移动智能与终端安全防护
  19. Electron:主进程、渲染进程以及通信
  20. 程序员如何优雅地使用 macOS?

热门文章

  1. 《LSTM: A Search Space Odyssey》翻译 Klaus Greff, Rupesh K. Srivastava, Jan Koutn´ık, Bas R. Steunebrink
  2. wxpython选择框_wxpython 对话框
  3. 超级计算机 更深的蓝 是什么,计算机“更深的蓝”具有智能吗
  4. “变声达人?入梦RVC变声器让你轻松变出不同的声音!”
  5. 杰理之开ble退出蓝牙模式卡死机【篇】
  6. 第四章 我国农民家庭经营
  7. 使用ZeroMemory、memset对结构体、数组的初始化
  8. 电表远程抄表系统如何保证数据传输的准确性
  9. UHF(EPC)标签使用常识
  10. 27.边缘系统的架构