文档章节

SPring AOP(面向切面编程)

MrBoyce
 MrBoyce
发布于 02/20 17:22
字数 2106
阅读 10
收藏 5

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吧,而且我们还需要在类中加点方法
@Bean
data class User(var name: String, var age: Int)
{
    fun add()
    {
        println("user add")
    }
}

@Bean
data 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方法中了
下面我就直接演示下其他几种的用法了
@Bean
data class User(var name: String, var age: Int)
{
    fun add(): String
    {
        println("user add")
        return "你好"
    }
}

@Bean
data 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>
1
2
然后在各方法上写上注解,别忘了类上面的注解
@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的注解扫描


结果自然毫无疑问
 

本文转载自:https://blog.csdn.net/UmGsoil/article/details/75003900 

共有 人打赏支持
MrBoyce
粉丝 4
博文 94
码字总数 38411
作品 0
成都
程序员
私信 提问
Spring面试,IoC和AOP的理解

spring 的优点? 1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易...

Sandy_wu
2013/06/08
0
0
spring面试题 对DI , AOP概念的理解

spring 的优点? 1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易...

罗荣熙
2012/11/12
0
0
Spring AOP解释及在项目中使用举例

一.AOP是什么 AOP - Aspect Oriented Programing,面向切面编程。将封装好的对象切开,找出其中对多个对象产生影响的公共行为,并将其封装为一个可重用的模块,这个模块被命名为“切面”,切...

Jacktanger
2018/06/08
0
0
《Spring5学习》04 - 面向切面编程

一、Spring面向切面编程的基本概念 面向切面编程(即AOP):把项目中需要再多处使用的功能比如日志、安全和事务等集中到一个类中处理,而不用在每个需要用到该功能的地方显式调用。 横切关注...

老韭菜
2018/08/19
0
0
SSM 五:Spring核心概念

第五章:Spring核心概念 一.Spring Ioc 优点:1.低侵入式设计2.独立于各种应用服务器3.依赖注入特性将组建关系透明化,降低耦合度4.面向切面编程的特性允许将通用性任务集中式处理5:使用第三...

廉价香水
2017/10/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

设计模式-适配器模式

一、什么是适配器? 适配器就是一种适配中间件,将两种不匹配的东西进行适配连接,举一个生活中的例子。小金最近买了最新款的macbook pro,但是发现电脑的数据接口都变成了Type c接口,这导致...

kimyeongnam
30分钟前
2
0
在没有 Emacs 的情况下使用 Org 模式

每到年初似乎总有这么一个疯狂的冲动来寻找提高生产率的方法。新年决心,正确地开始一年的冲动,以及“向前看”的态度都是这种冲动的表现。软件推荐通常都会选择闭源和专利软件。但这不是必须...

linux-tao
42分钟前
3
0
Krpano skin_settings解释

<skin_settings maps="false" 是否显示地图按钮 maps_type="google" 地图类型 maps_bing_api_key="" bing地图授权key maps_google_......

华山猛男
44分钟前
3
0
兼容率达78%!首份Android Q版本兼容性评测报告出炉

据《Android Q Beta 1版本—国内主流千款典型应用兼容性测试数据评测报告》显示,该版本兼容率为78%。 那么,千款主流应用在Android Q版本兼容情况表现如何,不兼容的主要原因是什么,又将如...

安卓绿色联盟
46分钟前
2
0
二维数组排序

以二维数组$arr中apply_num为数字降序排列:array_multisort(array_column($arr,'apply_num'),SORT_DESC,SORT_NUMERIC,$arr);...

郭周园
51分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部