慢慢进阶spring(三)之AOP

什么是AOP

传统的OOP开发中的代码逻辑是自上而下的,而这些过程会产生一些横切性问题,这些横切性的问题和我们的主业务逻辑关系不大,这些横切性问题不会影响到主逻辑实现的,但是会散落到代码的各个部分。AOP是处理一些横切性问题,AOP的编程思想就是把这些问题和主业务逻辑分开成为核心关注点以及与业务关系不大的横切关注点,达到与主业务逻辑解耦的目的。使代码的重用性和开发效率更高。

AOP在Spring框架中用于:

  • 提供声明式企业服务。最重要的此类服务是 声明式事务管理。
  • 让用户实现自定义方面,并用AOP补充其对OOP的使用。

spring AOP提供两种编程风格
基于注解:@AspectJ
基于xml文件:Schema-based AOP

理清AOP,spring AOP,AspectJ的关系:

  • Aop是一种概念。
  • springAop、AspectJ都是Aop的实现,Spring Aop有自己的语法,但是语法复杂,所以SpringAop借助了AspectJ的注解,但是底层实现还是spring自己的。

AOP概念和术语

  • Aspect:涉及多个类别的关注点的模块化。事务管理是企业Java应用程序中横切关注的一个很好的例子。在Spring AOP中,Aspect是通过使用常规类(基于模式的方法)或通过注释进行@Aspect注释的常规类 (@AspectJ样式)来实现的。
  • Join point:在程序执行过程中的一点,例如方法的执行或异常的处理。目标对象中的方法。
  • Advice:在特定的Join point处采取的操作。
  • Pointcut:与Advice匹配的谓词。Advice与Join point表达式关联,并在与该切入点匹配的任何连接点处运行。切点表示连接点的集合。
  • Target object:目标对象 也可叫 原始对象
  • Aop Proxy:代理对象 包含了原始对象的代码和增加后的代码的那个对象AOP代理:由AOP框架创建的一个对象,用于实现方面协定(建议方法执行等)。
  • Weaving:把代理逻辑加入到目标对象上的过程叫做织入

advice通知类型:

  • Before:连接点执行之前,但是无法阻止连接点的正常执行,除非该段执行抛出异常
  • After:连接点正常执行之后,执行过程中正常执行返回退出,非异常退出
  • After throwing:执行抛出异常的时候
  • After (finally):无论连接点是正常退出还是异常退出,都会执行
  • Around advice:围绕连接点执行,例如方法调用。这是最有用的切面方式。around通知可以在方法调用之前和之后执行自定义行为。它还负责选择是继续加入点还是通过返回自己的返回值或抛出异常来快速建议的方法执行。

不得不说的Proceedingjoinpoint 和JoinPoint

在使用advice在Join point处执行的方法,会经常使用到这两个参数Proceedingjoinpoint 和JoinPoint。比如以下两个代码:

@Around(value = "aspectPointCut()")
public Object around(ProceedingJoinPoint point){
    Object object = null;
    try {
        object = point.proceed();
        MethodSignature signature = (MethodSignature)point.getSignature();
        Method method = signature.getMethod();
        String value = method.getAnnotation(Log.class).value();//日志信息
        String methodName = method.getName();//方法名称
        String className = point.getTarget().getClass().getName();//类名
        String args = JSON.toJSONString(point.getArgs());//请求参数

        System.out.println("这个是环绕通知.....after。日志信息:"
                + value + ",访问方法:" + className+"."+methodName +"(),请求参数:" + args);
    }catch (Throwable throwable){
        throwable.printStackTrace();
    }
    return object;
}

@After(value = "aspectPointCut()")
public void after(JoinPoint point){
    MethodSignature signature = (MethodSignature)point.getSignature();

    Method method = signature.getMethod();
    String value = method.getAnnotation(Log.class).value();//日志信息
    String methodName = method.getName();//方法名称
    String className = point.getTarget().getClass().getName();//类名
    String args = JSON.toJSONString(point.getArgs());//请求参数
    System.out.println("这个是后置通知.....after。日志信息:"
            + value + ",访问方法:" + className+"."+methodName +"(),请求参数:" + args);
}

那么他们有什么作用以及却别呢??

Proceedingjoinpoint 继承了JoinPoint,proceed()这个是aop代理链执行的方法。并扩充实现了proceed()方法,用于继续执行连接点。JoinPoint仅能获取相关参数,无法执行连接点。

JoinPoin相关api

1.java.lang.Object[] getArgs():获取连接点方法运行时的入参列表;

2.Signature getSignature() :获取连接点的方法签名对象;

3.java.lang.Object getTarget() :获取连接点所在的目标对象;

4.java.lang.Object getThis() :获取代理对象本身;

proceed()有重载,有个带参数的方法,可以修改目标方法的的参数

springAop支持AspectJ(使用步骤)

1、启用@AspectJ支持

要使用Java @Configuration启用@AspectJ支持,请添加@EnableAspectJAutoProxy注释

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {

}

2、声明一个Aspect

申明一个@Aspect注释类,并且定义成一个bean交给Spring管理。

@Component
@Aspect
public class LogAspect {
}

3、在Aspect中申明一个pointCut

切入点表达式由@Pointcut注释表示。切入点声明由两部分组成:一个签名包含名称和任何参数,以及一个切入点表达式,该表达式确定我们对哪个方法执行。

/**
 * 申明Aspect,并且交给spring容器管理
 */
@Component
@Aspect
public class LogAspect {
    /**
     * 申明切入点,匹配标注Log注解的所有方法调用
     */
    @Pointcut(value = "@annotation(com.email.annotation.Log)")
    public void pintCut() {
        System.out.println("point cut");
    }
} 

4、在Aspect中申明一个Advice通知

advice通知与pointcut切入点表达式相关联,并在切入点匹配的方法执行@Before之前、@After之后或前后运行。

  /**
 * 申明Aspect,并且交给spring容器管理
 */
    @Aspect
@Component
public class LogAspect {
    
            /**
     * 申明切入点,匹配标注Log注解的所有方法调用
     */
    @Pointcut(value = "@annotation(com.email.annotation.Log)")
    private void aspectPointCut(){

    }

    @Before(value = "aspectPointCut()")
    public void before(JoinPoint point){
        MethodSignature signature = (MethodSignature)point.getSignature();
        Method method = signature.getMethod();
        String value = method.getAnnotation(Log.class).value();//日志信息
        String methodName = method.getName();//方法名称
        String className = point.getTarget().getClass().getName();//类名
        String args = JSON.toJSONString(point.getArgs());//请求参数
        System.out.println("这个是前置通知.....before。日志信息:"
                + value + ",访问方法:" + className+"."+methodName +"(),请求参数:" + args);
    }
    
    @Around(value = "aspectPointCut()")
    public Object around(ProceedingJoinPoint point){
        Object object = null;
        try {
            object = point.proceed();
            MethodSignature signature = (MethodSignature)point.getSignature();
            Method method = signature.getMethod();
            String value = method.getAnnotation(Log.class).value();//日志信息
            String methodName = method.getName();//方法名称
            String className = point.getTarget().getClass().getName();//类名
            String args = JSON.toJSONString(point.getArgs());//请求参数

            System.out.println("这个是环绕通知.....after。日志信息:"
                    + value + ",访问方法:" + className+"."+methodName +"(),请求参数:" + args);
        }catch (Throwable throwable){
            throwable.printStackTrace();
        }
        return object;
    }
}

spring Aop原理

spring Aop使用动态代理机制来实现。使用JDK动态代理或CGLIB创建给定目标对象的代理。JDK动态代理内置在JDK中,而CGLIB是常见的开源类定义库。

  • 如果要代理的目标对象实现了接口,则使用JDK动态代理。代理了由目标类型实现的所有接口。
  • 如果目标对象未实现任何接口,则将创建CGLIB代理。
  • 如果要强制使用CGLIB代理,可以使用在配置类上加注解@EnableAspectJAutoProxy(proxyTargetClass = true)。但是,应该考虑以下问题:如果使用CGLIB,那么对象不能有final修饰,因为CGLIB基于继承生成子类实现。

本人水平有限,难免有错误或遗漏之处,望大家指正和谅解,提出宝贵意见,愿与之交流。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • 基本知识 其实, 接触了这么久的 AOP, 我感觉, AOP 给人难以理解的一个关键点是它的概念比较多, 而且坑爹...
    永顺阅读 8,092评论 5 114
  • Spring AOP解决问题 相比较于面向过程程序设计(POP),面向对象程序设计(OOP)更加注重封装与隔离,以...
    桴海阅读 184评论 0 0
  • 概述 Spring是什么? Spring是一个开源框架,为了解决企业应用开发的复杂性而创建的,但是现在已经不止于企...
    琅筑阅读 1,153评论 2 8
  • **** AOP 面向切面编程 底层原理 代理!!! 今天AOP课程1、 Spring 传统 AOP2、 Spri...
    luweicheng24阅读 1,351评论 0 1
  • 杨柳青青,柳枝半垂,如同含羞的少女。 看到这株柳,我又一次想起了阿酿。 阿酿是酒馆老板的女儿,在一次旅途中我们在走...
    十言与鱼阅读 521评论 6 8