Spring框架中的AOP技术

Easter79
• 阅读 685

1、AOP概述

AOP技术即Aspect Oriented Programming的缩写,译为面向切面编程。AOP是OOP的一种延续,利用AOP技术可以对业务逻辑的各个部分进行隔离,从使得业务逻辑各部分之间的耦合性降低,提高程序的可重用性,同时提高了开发的效率。

AOP采用横向抽取机制,取代了传统纵向继承体系重复性代码,AOP可以在不修改源代码的前提下,对程序进行增强。

2、AOP技术的底层实现

  1. 基于jdk的动态代理:必须是面向接口的,只有实现了具体接口的类才能生成代理对象
  2. 基于CGLIB动态代理:对于没有实现接口的类,也可以产生代理,产生这个类的子类的方式

Spring的传统AOP中根据类是否实现接口而采用不同的代理方式,如果实现类接口,则使用jdk动态代理完成AOP,如果没有实现接口,采用CGLIB动态代理完成AOP。

JDK动态代理演示:

接口UserDao、实现类UserDaoImpl、动态代理类MyProxyUtils

1 package com.alphajuns.demo1;
2 
3 public interface UserDao {
4 
5     public void save();
6     
7     public void update();
8     
9 }

 1 package com.alphajuns.demo1;
 2 
 3 public class UserDaoImpl implements UserDao {
 4 
 5     @Override
 6     public void save() {
 7         System.out.println("保存用户...");
 8     }
 9 
10     @Override
11     public void update() {
12         System.out.println("修改用户...");
13     }
14 
15 }

 1 package com.alphajuns.demo1;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 import java.lang.reflect.Proxy;
 6 
 7 /*
 8  * 使用JDK的方式生成动态代理
 9  */
10 public class MyProxyUtils {
11 
12     public static UserDao getProxy(final UserDao dao) {
13         // 使用Proxy类生成代理对象
14         UserDao proxy = (UserDao) Proxy.newProxyInstance(
15                 dao.getClass().getClassLoader(),
16                 dao.getClass().getInterfaces(),
17                 new InvocationHandler() {
18                     
19                     @Override
20                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
21                         if ("save".equals(method.getName())) {
22                             System.out.println("记录日志...");
23                         }
24                         // 执行dao类中的方法
25                         return method.invoke(dao, args);
26                     }
27                 });
28         
29         // 返回代理对象
30         return proxy;
31     }
32     
33 }

CGLIB代理:

 1 package com.alphajuns.demo2;
 2 
 3 import java.lang.reflect.Method;
 4 
 5 import org.springframework.cglib.proxy.Enhancer;
 6 import org.springframework.cglib.proxy.MethodInterceptor;
 7 import org.springframework.cglib.proxy.MethodProxy;
 8 
 9 public class MyCglibUtils {
10 
11     /*
12      * 使用Cglib方法生成代理对象
13      */
14     public static BookDaoImpl getProxy() {
15         Enhancer enhancer = new Enhancer();
16         // 设置父类
17         enhancer.setSuperclass(BookDaoImpl.class);
18         // 设置回调函数
19         enhancer.setCallback(new MethodInterceptor() {
20             // 代理对象的方法执行,回调函数的方法就会执行
21             @Override
22             public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
23                 if ("save".equals(method.getName())) {
24                     System.out.println("记录日志...");
25                 }
26                 // 正常执行
27                 return methodProxy.invokeSuper(obj, args);
28             }
29         });
30         
31         // 生成代理对象
32         BookDaoImpl proxy = (BookDaoImpl) enhancer.create();
33         return proxy;
34     }
35     
36 }

3、AOP相关术语

  1. JoinPoint(连接点):被拦截的点。Spring中,这些点是指方法,Spring只支持方法类型的连接点。
  2. Pointcut(切入点):对需要被拦截的JoinPoint的定义。
  3. Advice(通知/增强):拦截到JointPoint之后所要做的事情就是通知。通知分为前置通知、后置通知、异常通知、最终通知、环绕通知
  4. Introduction(引介):引介是一种特殊的通知,在不修改代码的前提下,Introduction可以在运行期为类动态地添加一些方法或field
  5. Target(目标对象):代理的目标对象
  6. Weaving(织入):是指增强应用到目标对象来创建新的代理对象的过程
  7. Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
  8. Aspect(切面):切入点与通知的结合

4、XML方式AOP开发步骤

  1. 创建WEB项目,引入jar包
  2. 创建Spring配置文件,引入AOP的schema约束
  3. 创建包结构,编写具体的接口和实现类
  4. 将目标类配置到Spring配置文件中
  5. 定义切面类
  6. 在配置文件中定义切面类
  7. 在配置文件中完成AOP配置
  8. 测试

5、切入点表达式

切入点表达式在下面applicationContext2中以注释形式进行了介绍。

6、AOP通知类型

  1. 前置通知:在目标类的方法执行之前执行
  2. 后置通知:在目标类方法执行之后执行
  3. 异常抛出通知:在抛出异常后通知
  4. 环绕通知:方法执行前后都执行

7、AOP应用举例

接口CustomerDao、实现类CustomerDaoImpl、切面类MyAspectXml、Spring配置文件applicationContext、applicationContext2、applicationContext3

1 package com.alphajuns.demo3;
2 
3 public interface CustomerDao {
4 
5     public void save();
6     
7     public void update();
8     
9 }

 1 package com.alphajuns.demo3;
 2 
 3 public class CustomerDaoImpl implements CustomerDao {
 4 
 5     @Override
 6     public void save() {
 7         System.out.println("保存客户...");
 8     }
 9 
10     @Override
11     public void update() {
12         System.out.println("更新客户...");
13     }
14 
15 }

 1 package com.alphajuns.demo3;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 
 5 /*
 6  * 切面类:切入点+通知
 7  */
 8 public class MyAspectXml {
 9 
10     /*
11      * 通知(具体的增强)
12      */
13     public void log() {
14         System.out.println("记录日志...");
15     }
16     
17     /*
18      * 最终通知:方法执行成功或出现异常,都会执行
19      */
20     public void after() {
21         System.out.println("最终通知...");
22     }
23     
24     /*
25      * 后置通知:方法执行之后,执行后置通知,出现异常则不执行
26      */
27     public void afterReturn() {
28         System.out.println("后置通知...");
29     }
30     
31     /*
32      * 环绕通知:方法执行之前和方法执行之后进行通知,默认情况下,目标对象的方法不执行。需要手动让目标对象的方法执行
33      */
34     public void around(ProceedingJoinPoint joinPoint) {
35         System.out.println("环绕通知1...");
36         try {
37             // 手动让目标对象的方法执行
38             joinPoint.proceed();
39         } catch (Throwable e) {
40             e.printStackTrace();
41         }
42         System.out.println("环绕通知2...");
43     }
44     
45 }

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
 5         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 6         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
 7 
 8     <!-- 配置客户的dao -->
 9     <bean id="customerDao" class="com.alphajuns.demo3.CustomerDaoImpl"/>
10     <!-- 配置切面类 -->
11     <bean id="myAspectXml" class="com.alphajuns.demo3.MyAspectXml"/>
12     <!-- 配置AOP -->
13     <aop:config>
14         <!-- 配置切面类:切入点+通知类型 -->
15         <aop:aspect ref="myAspectXml">
16             <!-- 配置前置通知 -->
17             <aop:before method="log" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/>
18         </aop:aspect>
19     </aop:config>
20 
21 </beans>

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
 5         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 6         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
 7 
 8     <!-- 配置客户的dao -->
 9     <bean id="customerDao" class="com.alphajuns.demo3.CustomerDaoImpl"/>
10     <!-- 配置切面类 -->
11     <bean id="myAspectXml" class="com.alphajuns.demo3.MyAspectXml"/>
12     <!-- 配置AOP -->
13     <aop:config>
14         <!-- 配置切面类:切入点+通知类型 -->
15         <aop:aspect ref="myAspectXml">
16             <!-- 配置前置通知 -->
17             <!-- 切入点的表达式
18                 1、execution() 固定的,不能不写
19                 2、public 可以省略不写
20                 3、void出可以用*替代,表示返回值类型任意,不能省略不写
21                 4、包的简写方式
22                 5、类的写法
23                 6、方法的写法
24                 7、方法的参数
25              -->
26             <!-- 完整写法 -->
27             <!-- <aop:before method="log" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/> -->
28             <!-- public可以省略不写 -->
29             <!-- <aop:before method="log" pointcut="execution(void com.alphajuns.demo3.CustomerDaoImpl.save())"/> -->
30             <!-- void出用*替代 -->
31             <!-- <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.CustomerDaoImpl.save())"/> -->
32             <!-- 包的写法 -->
33             <!-- <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.CustomerDaoImpl.save())"/> -->
34             <!-- 包的写法 -->
35             <!-- <aop:before method="log" pointcut="execution(* *..*.CustomerDaoImpl.save())"/> -->
36             <!-- 类的写法 -->
37             <!-- <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.*DaoImpl.save())"/> -->
38             <!-- 方法写法 -->
39             <!-- <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.CustomerDaoImpl.*save())"/> -->
40             <!-- 方法的参数 -->
41             <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.CustomerDaoImpl.*save(..))"/>
42         </aop:aspect>
43     </aop:config>
44 
45 </beans>

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
 5         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 6         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
 7 
 8     <!-- 配置客户的dao -->
 9     <bean id="customerDao" class="com.alphajuns.demo3.CustomerDaoImpl"/>
10     <!-- 配置切面类 -->
11     <bean id="myAspectXml" class="com.alphajuns.demo3.MyAspectXml"/>
12     <!-- 配置AOP -->
13     <aop:config>
14         <!-- 配置切面类:切入点+通知类型 -->
15         <aop:aspect ref="myAspectXml">
16             <!-- 配置前置通知 -->
17             <!-- <aop:before method="log" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/> -->
18             <!-- 配置后置通知 -->
19             <!-- <aop:after method="log" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/> -->
20             <!-- 环绕通知 -->
21             <aop:around method="around" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/>
22         </aop:aspect>
23     </aop:config>
24 
25 </beans>
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
kenx kenx
3年前
SpringBoot Aop 详解和多种使用场景
前言aop面向切面编程,是编程中一个很重要的思想本篇文章主要介绍的是SpringBoot切面Aop的使用和案例什么是aopAOP(AspectOrientedProgramming):面向切面编程,面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
AOP相关概念
1.AOP(面向切面编程)在软件业,AOP为AspectOrientedProgramming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,在软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型.利用AOP
Easter79 Easter79
3年前
Spring的AOP逐层深入——AOP的基本原理(六)
什么是AOP    AOP(AspectOrientedProgramming),意思是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP基于IoC基础,是对OOP(ObjectOrientedProgramming,面向对象)的延续。同时,AOP实际是GOF设计模式的延续,设计模式孜孜不倦
Wesley13 Wesley13
3年前
Spring AOP教程
一、概念AOP(AspectOrientedProgramming):面向切面编程。面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。二、用途日志记
Wesley13 Wesley13
3年前
Spring学习总结(4)——Spring AOP教程
一、概念AOP(AspectOrientedProgramming):面向切面编程。面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。二、用途日志记
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k