Kotlin的Spring之旅(二):AOP(面向切面编程)
来源:互联网 发布:大二申请国外大学知乎 编辑:程序博客网 时间:2024/06/11 15:55
AOP(面向切面编程)
AOP是OOP(面向对象编程)的延续,但是它和面向对象的纵向编程不同,它是一个横向的切面式的编程。可以理解为oop就是一根柱子,如果需要就继续往上加长,而aop则是在需要的地方把柱子切开,在中间加上一层,再把柱子完美的粘合起来。
用物理上的话来说,aop就是给这个编程世界加上了一个维度,二维到三维的差别。很明显aop要灵活得多
AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。
AOP核心概念
- Joinpoint(连接点):指那些被拦截到的点(spring中这些点指的是方法)
- Pointcut(切入点):指我们要对哪些joinpoint进行拦截的定义
- Advice(通知/增强):拦截到joinpoint之后多要做的事情就是通知(通知分为前置通知,后置通知,异常通知,最终通知,环绕通知)
- Introduction(引介):引介是一种特殊的通知。在不改变代码的前提下,introduction可以在运行期间为类动态日案件一些方法或Field
- Target(目标对象):代理的目标对象(需要增强的类)
- Weaving(织入):把增强应用到目标的过程(advice应用到target的过程)
- Proxy(代理):一个类被AOP织入增强后,就会产生一个结果代理类
Aspect(切面):是切入点和通知(引介)的结合
看不懂吧<( ̄︶ ̄)>,因为我之前也没看懂,没事,我们写几个例子看看就能懂了。如果你没学过还能看懂,那我也只能膜拜大佬了
概念说完,下面开始进入正式环节
第一步 添加依赖
想使用AOP光凭之前的那些还是不够的,所以我们还需要添加一些依赖
compile "org.springframework:spring-aspects:4.3.9.RELEASE"compile "org.springframework:spring-aop:4.3.9.RELEASE"compile "aspectj:aspectjweaver:1.5.4"compile "aopalliance:aopalliance:1.0"
这里面的aspectj可以看到,并不是spring的一部分,但是自从spring2之后,官方就添加了对aspectj的支持,而且现在spring官方是推荐使用aspectj来开发aop,我们自然要跟随官方的大旗走了
aspectj实现aop有两种方式,而且还是老两种
- xml配置
- 注解实现
我们来看这两种,和之前一样,我们常用的肯定还是能少写代码的注解方式,xml配置的方式看看就可以了,但是至少也要能看懂,不然别人写了你看不懂就尴尬了
1. xml配置
首先在我们的xml文件中加入约束
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
可以看到我们又加上了aop的约束
我们还是继续用我们的User类不过这次一个类不够用,我们需要再来一个类就叫Advice吧,而且我们还需要在类中加点方法
@Beandata class User(var name: String, var age: Int){ fun add() { println("user add") }}@Beandata class Advice(var content: String){ fun before() { println("前置通知") }}
然后就是配置xml了,我们通过xml来配置切入点(pointcut),这里我们需要用到一个函数
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
来点例子看一下:
- 匹配所有public的方法:
execution(public * *(..))
- 匹配包下所有类的方法:
execution(* com.kotlin.*(..))
(一个点表示不包含子包) execution(* com.kotlin.. *(..))
(两个点表示包含子包)- 匹配实现特定接口的所有类的方法:
execution(* com.kotlin.xxinterface+.*(..))
- 匹配所有add开头的方法:
execution(* add*(..))
- 匹配所有方法:
execution(* *.*(..))
这样大概清楚了吧,下面我们我们来写一个前置通知增强User中的add方法
<!--1.配置对象--> <bean id="user" class="com.kotlin.Bean.User"></bean> <bean id="advice" class="com.kotlin.Bean.Advice"></bean> <!--2.配置aop操作--> <aop:config> <!--2.1配置切入点 因为User中只有一个方法,就直接增强User中的所有方法了--> <aop:pointcut id="pointcut" expression="execution(* com.kotlin.Bean.User.*(..))"/> <!--2.2配置切面 将增强用到方法上--> <aop:aspect ref="advice"> <!--选择用来增强的方法和需要增强的切入点--> <aop:before method="before" pointcut-ref="pointcut"/> </aop:aspect> </aop:config>
然后来到我们的测试类,运行下看看
class main{ @Test fun test() { //加载Spring配置文件,创建对象 val context = FileSystemXmlApplicationContext("src/main/webapp/WEB-INF/applicationContext.xml") val user = context.getBean("user") as User user.add() }}
结果可以看到,before方法已经添加到add方法中了
下面我就直接演示下其他几种的用法了
@Beandata class User(var name: String, var age: Int){ fun add(): String { println("user add") return "你好" }}@Beandata class Advice(var content: String){ fun before() { println("前置通知") } //后置通知需要传入一个参数,这个参数就是需要增强方法的返回值,没有可以不写 fun afterResult(result: Any) { println("后置通知 "+result) } //最终通知无论该方法有没有出异常有没有返回值,最终都会被执行 fun after() { println("最终通知") } /* 环绕通知需要一个ProceedingJoinPoint参数,这相当于需要增强的函数的方法体,需要的调用它的proceed方法执行,如果该函数有返回值,那么环绕通知也需要返回一个proceed方法的返回值 */ fun around(pro: ProceedingJoinPoint): Any { //方法之前 println("环绕通知 方法之前") //被增强的方法 val any = pro.proceed() //方法之后 println("环绕通知 方法之后") return any } //异常通知需要一个异常参数,当出现异常时该方法将会被调用 fun exception(ex : Exception) { println("异常通知 "+ex) }}
<!--1.配置对象--> <bean id="user" class="com.kotlin.Bean.User"></bean> <bean id="advice" class="com.kotlin.Bean.Advice"></bean> <!--2.配置aop操作--> <aop:config> <!--2.1配置切入点--> <aop:pointcut id="pointcut" expression="execution(* com.kotlin.Bean.User.*(..))"/> <!--2.2配置切面 将增强用到方法上--> <aop:aspect ref="advice"> <!--选择用来增强的方法和需要增强的切入点--> <aop:before method="before" pointcut-ref="pointcut"/> <!--后置通知需要配置它的参数--> <aop:after-returning method="afterResult" pointcut-ref="pointcut" returning="result"/> <aop:after method="after" pointcut-ref="pointcut" /> <aop:around method="around" pointcut-ref="pointcut" /> <!--异常通知也要配置它的异常参数--> <aop:after-throwing method="exception" pointcut-ref="pointcut" throwing="ex"/> </aop:aspect> </aop:config>
然后我们来看下结果
接着,我们手动给他制造一个异常,就用4/0吧
可以看到,后置通知和后环绕通知没有了,取而代之的是除零异常,这时异常通知出现了,这也说明了后置通知只有在没有异常时候才会执行,异常通知只会在有异常时候执行
这也得出了这样的结论
try{ // 前置通知 // 环绕通知(前) // 目标方法 // 环绕通知(后) // 后置通知(也有人称为返回通知)}catche(Exception e){ // 异常通知}finally{ // 最终通知}
2.注解配置
注解配置很简单,直接把内容写在方法的头上就可以了,我把代码给出,大家一看就知道了
首先在xml中开启自动扫描
<!--开启aop自动扫描代理--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
然后在各方法上写上注解,别忘了类上面的注解
@Bean@Component(value = "user")data class User(var name: String, var age: Int){ fun add(): String { println("user add")// var s = 4 / 0 return "你好" }}@Aspect@Bean@Component(value = "advice")data class Advice(var content: String){ @Before(value = "execution(* com.kotlin.Bean.User.*(..))") fun before() { println("前置通知") } @AfterReturning(value = "execution(* com.kotlin.Bean.User.*(..))", returning = "result") fun afterResult(result: Any) { println("后置通知 " + result) } @After(value = "execution(* com.kotlin.Bean.User.*(..))") fun after() { println("最终通知") } @Around(value = "execution(* com.kotlin.Bean.User.*(..))") fun around(pro: ProceedingJoinPoint): Any { //方法之前 println("环绕通知 方法之前") //被增强的方法 val any = pro.proceed() //方法之后 println("环绕通知 方法之后") return any } @AfterThrowing(value = "execution(* com.kotlin.Bean.User.*(..))", throwing = "ex") fun exception(ex: Exception) { println("异常通知 " + ex) }}
别忘了开启IOC的注解扫描
结果自然毫无疑问
阅读全文
1 0
- Kotlin的Spring之旅(二):AOP(面向切面编程)
- Spring之AOP(面向切面编程)
- Spring之AOP(面向切面编程)
- Spring 的面向切面编程(AOP)
- spring学习(二)AOP面向切面编程
- Spring框架(二)--AOP面向切面编程
- Spring配置过程 (二)面向切面编程AOP
- Spring学习之旅(二) AOP(面向切面编程)的使用
- SSM框架 之 Spring-AOP(面向切面编程)
- SSM框架 之 Spring-AOP(面向切面编程)
- Spring初探之AOP(面向切面编程)
- Spring AOP 面向切面编程(一)
- Spring实践:面向切面编程(AOP)
- Spring 面向切面(AOP)编程,注解
- Spring面向切面编程AOP(around)
- Spring AOP(面向切面编程)
- Spring核心AOP(面向切面编程)
- Spring---面向切面编程(aop)实例
- 暴力(Cake,HDU 5355)
- DOM中的一些概念
- UDS的CAN刷新软件
- Codis2迁移到Codis3
- Navigation Drawer的基本用法(SlidingMenu的替代品)
- Kotlin的Spring之旅(二):AOP(面向切面编程)
- 电商时代已经要过去了。接下来是零售
- day01
- 使用Web Worker
- Redux(1)
- Hdu 1531 King 差分约束 解题报告
- HDU-2571-命运
- 悲观锁和乐观锁的区别和应用场景
- netty工程,JAVA解析BCD码,BIN码