Spring框架中的AOP技术

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

11 package com.alphajuns.demo1; 22 33 public interface UserDao { 44 55 public void save(); 66 77 public void update(); 88 99 } 10 11 1 package com.alphajuns.demo1; 12 2 13 3 public class UserDaoImpl implements UserDao { 14 4 15 5 @Override 16 6 public void save() { 17 7 System.out.println("保存用户..."); 18 8 } 19 9 2010 @Override 2111 public void update() { 2212 System.out.println("修改用户..."); 2313 } 2414 2515 } 26 27 1 package com.alphajuns.demo1; 28 2 29 3 import java.lang.reflect.InvocationHandler; 30 4 import java.lang.reflect.Method; 31 5 import java.lang.reflect.Proxy; 32 6 33 7 /* 34 8 * 使用JDK的方式生成动态代理 35 9 */ 3610 public class MyProxyUtils { 3711 3812 public static UserDao getProxy(final UserDao dao) { 3913 // 使用Proxy类生成代理对象 4014 UserDao proxy = (UserDao) Proxy.newProxyInstance( 4115 dao.getClass().getClassLoader(), 4216 dao.getClass().getInterfaces(), 4317 new InvocationHandler() { 4418 4519 @Override 4620 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 4721 if ("save".equals(method.getName())) { 4822 System.out.println("记录日志..."); 4923 } 5024 // 执行dao类中的方法 5125 return method.invoke(dao, args); 5226 } 5327 }); 5428 5529 // 返回代理对象 5630 return proxy; 5731 } 5832 5933 }

CGLIB代理:

1 1 package com.alphajuns.demo2; 2 2 3 3 import java.lang.reflect.Method; 4 4 5 5 import org.springframework.cglib.proxy.Enhancer; 6 6 import org.springframework.cglib.proxy.MethodInterceptor; 7 7 import org.springframework.cglib.proxy.MethodProxy; 8 8 9 9 public class MyCglibUtils { 1010 1111 /* 1212 * 使用Cglib方法生成代理对象 1313 */ 1414 public static BookDaoImpl getProxy() { 1515 Enhancer enhancer = new Enhancer(); 1616 // 设置父类 1717 enhancer.setSuperclass(BookDaoImpl.class); 1818 // 设置回调函数 1919 enhancer.setCallback(new MethodInterceptor() { 2020 // 代理对象的方法执行,回调函数的方法就会执行 2121 @Override 2222 public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { 2323 if ("save".equals(method.getName())) { 2424 System.out.println("记录日志..."); 2525 } 2626 // 正常执行 2727 return methodProxy.invokeSuper(obj, args); 2828 } 2929 }); 3030 3131 // 生成代理对象 3232 BookDaoImpl proxy = (BookDaoImpl) enhancer.create(); 3333 return proxy; 3434 } 3535 3636 }

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

11 package com.alphajuns.demo3; 22 33 public interface CustomerDao { 44 55 public void save(); 66 77 public void update(); 88 99 } 10 11 1 package com.alphajuns.demo3; 12 2 13 3 public class CustomerDaoImpl implements CustomerDao { 14 4 15 5 @Override 16 6 public void save() { 17 7 System.out.println("保存客户..."); 18 8 } 19 9 2010 @Override 2111 public void update() { 2212 System.out.println("更新客户..."); 2313 } 2414 2515 } 26 27 1 package com.alphajuns.demo3; 28 2 29 3 import org.aspectj.lang.ProceedingJoinPoint; 30 4 31 5 /* 32 6 * 切面类:切入点+通知 33 7 */ 34 8 public class MyAspectXml { 35 9 3610 /* 3711 * 通知(具体的增强) 3812 */ 3913 public void log() { 4014 System.out.println("记录日志..."); 4115 } 4216 4317 /* 4418 * 最终通知:方法执行成功或出现异常,都会执行 4519 */ 4620 public void after() { 4721 System.out.println("最终通知..."); 4822 } 4923 5024 /* 5125 * 后置通知:方法执行之后,执行后置通知,出现异常则不执行 5226 */ 5327 public void afterReturn() { 5428 System.out.println("后置通知..."); 5529 } 5630 5731 /* 5832 * 环绕通知:方法执行之前和方法执行之后进行通知,默认情况下,目标对象的方法不执行。需要手动让目标对象的方法执行 5933 */ 6034 public void around(ProceedingJoinPoint joinPoint) { 6135 System.out.println("环绕通知1..."); 6236 try { 6337 // 手动让目标对象的方法执行 6438 joinPoint.proceed(); 6539 } catch (Throwable e) { 6640 e.printStackTrace(); 6741 } 6842 System.out.println("环绕通知2..."); 6943 } 7044 7145 } 72 73 1 <?xml version="1.0" encoding="UTF-8"?> 74 2 <beans xmlns="http://www.springframework.org/schema/beans" 75 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 76 4 xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" 77 5 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 78 6 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here --> 79 7 80 8 <!-- 配置客户的dao --> 81 9 <bean id="customerDao" class="com.alphajuns.demo3.CustomerDaoImpl"/> 8210 <!-- 配置切面类 --> 8311 <bean id="myAspectXml" class="com.alphajuns.demo3.MyAspectXml"/> 8412 <!-- 配置AOP --> 8513 <aop:config> 8614 <!-- 配置切面类:切入点+通知类型 --> 8715 <aop:aspect ref="myAspectXml"> 8816 <!-- 配置前置通知 --> 8917 <aop:before method="log" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/> 9018 </aop:aspect> 9119 </aop:config> 9220 9321 </beans> 94 95 1 <?xml version="1.0" encoding="UTF-8"?> 96 2 <beans xmlns="http://www.springframework.org/schema/beans" 97 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 98 4 xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" 99 5 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 100 6 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here --> 101 7 102 8 <!-- 配置客户的dao --> 103 9 <bean id="customerDao" class="com.alphajuns.demo3.CustomerDaoImpl"/> 10410 <!-- 配置切面类 --> 10511 <bean id="myAspectXml" class="com.alphajuns.demo3.MyAspectXml"/> 10612 <!-- 配置AOP --> 10713 <aop:config> 10814 <!-- 配置切面类:切入点+通知类型 --> 10915 <aop:aspect ref="myAspectXml"> 11016 <!-- 配置前置通知 --> 11117 <!-- 切入点的表达式 11218 1、execution() 固定的,不能不写 11319 2public 可以省略不写 11420 3void出可以用*替代,表示返回值类型任意,不能省略不写 11521 4、包的简写方式 11622 5、类的写法 11723 6、方法的写法 11824 7、方法的参数 11925 --> 12026 <!-- 完整写法 --> 12127 <!-- <aop:before method="log" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/> --> 12228 <!-- public可以省略不写 --> 12329 <!-- <aop:before method="log" pointcut="execution(void com.alphajuns.demo3.CustomerDaoImpl.save())"/> --> 12430 <!-- void出用*替代 --> 12531 <!-- <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.CustomerDaoImpl.save())"/> --> 12632 <!-- 包的写法 --> 12733 <!-- <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.CustomerDaoImpl.save())"/> --> 12834 <!-- 包的写法 --> 12935 <!-- <aop:before method="log" pointcut="execution(* *..*.CustomerDaoImpl.save())"/> --> 13036 <!-- 类的写法 --> 13137 <!-- <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.*DaoImpl.save())"/> --> 13238 <!-- 方法写法 --> 13339 <!-- <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.CustomerDaoImpl.*save())"/> --> 13440 <!-- 方法的参数 --> 13541 <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.CustomerDaoImpl.*save(..))"/> 13642 </aop:aspect> 13743 </aop:config> 13844 13945 </beans> 140 141 1 <?xml version="1.0" encoding="UTF-8"?> 142 2 <beans xmlns="http://www.springframework.org/schema/beans" 143 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 144 4 xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" 145 5 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 146 6 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here --> 147 7 148 8 <!-- 配置客户的dao --> 149 9 <bean id="customerDao" class="com.alphajuns.demo3.CustomerDaoImpl"/> 15010 <!-- 配置切面类 --> 15111 <bean id="myAspectXml" class="com.alphajuns.demo3.MyAspectXml"/> 15212 <!-- 配置AOP --> 15313 <aop:config> 15414 <!-- 配置切面类:切入点+通知类型 --> 15515 <aop:aspect ref="myAspectXml"> 15616 <!-- 配置前置通知 --> 15717 <!-- <aop:before method="log" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/> --> 15818 <!-- 配置后置通知 --> 15919 <!-- <aop:after method="log" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/> --> 16020 <!-- 环绕通知 --> 16121 <aop:around method="around" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/> 16222 </aop:aspect> 16323 </aop:config> 16424 16525 </beans>
点赞
收藏

评论区

加载中...

相关推荐

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

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

SpringBoot Aop 详解和多种使用场景

前言aop面向切面编程,是编程中一个很重要的思想本篇文章主要介绍的是SpringBoot切面Aop的使用和案例什么是aopAOP(AspectOrientedProgramming):面向切面编程,面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )