【小家Spring】Spring AOP的多种使用方式以及神一样的AspectJ-AOP使用介绍(下)

简介: 【小家Spring】Spring AOP的多种使用方式以及神一样的AspectJ-AOP使用介绍(下)

AspectJ的织入方式及其原理概要


对于织入这个概念,可以简单理解为aspect(切面)应用到目标函数(类)的过程。对于这个过程,一般分为动态织入和静态织入,动态织入的方式是在运行时动态将要增强的代码织入到目标类中,这样往往是通过动态代理技术完成的,如Java JDK的动态代理(Proxy,底层通过反射实现)或者CGLIB的动态代理(底层通过继承实现),Spring AOP采用的就是基于运行时增强的代理技术,这点另一篇博文已经有分析了,这里主要重点分析一下静态织入。


ApectJ采用的就是静态织入的方式。ApectJ主要采用的是编译期织入,在这个期间使用AspectJ的acj编译器(类似javac)把aspect类编译成class字节码后,在java目标类编译时织入,即先编译aspect类再编译目标类。


image.png


关于ajc编译器,是一种能够识别aspect语法的编译器,它是采用java语言编写的,由于javac并不能识别aspect语法,便有了ajc编译器,注意ajc编译器也可编译java文件。为了更直观了解aspect的织入方式,我们打开前面案例中已编译完成的HelloWord.class文件,反编译后的java代码如下:


//编译后织入aspect类的HelloWord字节码反编译类
public class HelloWord {
    public HelloWord() {
    }
    public void sayHello() {
        System.out.println("hello world !");
    }
    public static void main(String[] args) {
        HelloWord helloWord = new HelloWord();
        HelloWord var10000 = helloWord;
   try {
        //MyAspectJDemo 切面类的前置通知织入
        MyAspectJDemo.aspectOf().ajc$before$com_zejian_demo_MyAspectJDemo$1$22c5541();
        //目标类函数的调用
           var10000.sayHello();
        } catch (Throwable var3) {
        MyAspectJDemo.aspectOf().ajc$after$com_zejian_demo_MyAspectJDemo$2$4d789574();
            throw var3;
        }
        //MyAspectJDemo 切面类的后置通知织入 
        MyAspectJDemo.aspectOf().ajc$after$com_zejian_demo_MyAspectJDemo$2$4d789574();
    }
}


显然AspectJ的织入原理已很明朗了,当然除了编译期织入,还存在链接期(编译后)织入,即将aspect类和java目标类同时编译成字节码文件后,再进行织入处理,这种方式比较有助于已编译好的第三方jar和Class文件进行织入操作,由于这不是本篇的重点,暂且不过多分析,掌握以上AspectJ知识点就足以协助理解Spring AOP了

Spring AOP的优点


Spring AOP 与ApectJ 的目的一致,都是为了统一处理横切业务,但与AspectJ不同的是,Spring AOP 并不尝试提供完整的AOP功能(即使它完全可以实现),Spring AOP 更注重的是与Spring IOC容器的结合,并结合该优势来解决横切业务的问题,因此在AOP的功能完善方面,相对来说AspectJ具有更大的优势


同时,Spring注意到AspectJ在AOP的实现方式上依赖于特殊编译器(ajc编译器),因此Spring很机智回避了这点,转向采用动态代理技术的实现原理来构建Spring AOP的内部机制(动态织入),这是与AspectJ(静态织入)最根本的区别。


在AspectJ 1.5后,引入@Aspect形式的注解风格的开发,Spring也非常快地跟进了这种方式,因此Spring 2.0后便使用了与AspectJ一样的注解。请注意,Spring 只是使用了与 AspectJ 5 一样的注解,但仍然没有使用 AspectJ 的编译器,底层依是动态代理技术的实现,因此并不依赖于 AspectJ 的编译器


再说区别和联系


AspectJ


AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件(只是我们Spring一般只用到它的注解,其余都是Spring自己实现的)。

Spring AOP


Spring提供了四种类型(说三种也对)的Aop支持:


1.基于经典的SpringAOP


      1.使用ProxyFactoryBean创建Bean。显然已经过时了,因为每个Bean你都使用它包装一下,麻烦


     2.引入自动代理创建器。如:AbstractAutoProxyCreator的所有子类,实现有多种。(EnableAspectJAutoProxy注解驱动原理就是它)

             前置通知:org.springframework.aop.MethodBeforeAdvice


             后置通知:org.springframework.aop.AfterReturningAdvice


             异常通知:org.springframework.aop.ThrowsAdvice


             环绕通知:org.aopalliance.intercept.MethodInterceptor (注意这个是aopalliance包下的接口,Spring提供实现类非常之多,比如:MethodBeforeAdviceInterceptor(包装了MethodBeforeAdvice),CacheInterceptor等等非常多)


2.纯POJO切面


      这个方式也就比较古老了,纯基于xml,简单例子如下:



  <-- Spring Aop的命名空间可以将纯POJO转换为切面,实际上这些POJO只是提供了满足切点的条件时所需要调用的方法,但是,这种技术需要XML进行配置,不能支持注解  -->
  <bean id="pojoAdvice" class="com.njust.learning.spring.pojoaop.PojoAdvice"></bean>
    <aop:config>
        <aop:pointcut id="p" expression="execution (* *.add(..))"/>
        <aop:aspect ref="pojoAdvice">
            <aop:before method="before" pointcut-ref="p"></aop:before>
            <!--通过设置returning来将返回值传递给通知-->
            <aop:after-returning method="after" pointcut-ref="p" returning="returnval"/>
            <aop:around method="around" pointcut-ref="p"/>
            <!--通过设置returning来将异常对象传递给通知-->
            <aop:after-throwing method="afterThrowing" pointcut-ref="p" throwing="e"/>
        </aop:aspect>
    </aop:config>


3.@ASpectJ注解驱动的切面


  1. 需要注意的是,Spring只使用到了它的注解功能,并不使用它的核心功能。核心解析功能由Spring自己实现的


@Aspect
public class HelloAspect {
    @Pointcut("execution(* com.fsx.service.*.*(..)) ")
    public void point() {
    }
    @Before("point()")
    public void before() {
        System.out.println("this is from HelloAspect#before...");
    }
    @After("point()")
    public void after() {
        System.out.println("this is from HelloAspect#after...");
    }
    @AfterReturning("point()")
    public void afterReturning() {
        System.out.println("this is from HelloAspect#afterReturning...");
    }
    @AfterThrowing("point()")
    public void afterThrowing() {
        System.out.println("this is from HelloAspect#afterThrowing...");
    }
    // 此处需要注意:若写了@Around方法,那么最后只会执行@Around和@AfterReturning 其它的都不会执行
    //@Around("point()")
    //public void around() {
    //    System.out.println("this is from HelloAspect#around...");
    //}
}


4.注入式AspectJ切面(其实与Spring并无多大的关系,这个就是使用AspectJ这个框架实现Aop编程) 需用用到AspectJ自己的编译器,因此其实也可以说这个不属于Spring的

  1. 这种方式上面已经做了案例了,此处忽略(使用较少,但Spring也给与了支持)


联系

我们借助于Spring Aop的命名空间可以将纯POJO转换为切面,实际上这些POJO只是提供了满足切点的条件时所需要调用的方法,但是,这种技术需要XML进行配置,不能支持注解


所以spring借鉴了AspectJ的切面,以提供注解驱动的AOP,本质上它依然是Spring基于代理的AOP,只是编程模型与AspectJ完全一致,这种风格的好处就是不需要使用XML进行配置(XML方式已经淘汰嘛,哈哈)


最后

博主希望通过本文,让读者能够了解到Spring AOP和AspectJ的区别与联系。


相关文章
|
2月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
7天前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
20天前
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理
|
2月前
|
XML Java 数据格式
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
这篇文章是Spring5框架的AOP切面编程教程,通过XML配置方式,详细讲解了如何创建被增强类和增强类,如何在Spring配置文件中定义切入点和切面,以及如何将增强逻辑应用到具体方法上。文章通过具体的代码示例和测试结果,展示了使用XML配置实现AOP的过程,并强调了虽然注解开发更为便捷,但掌握XML配置也是非常重要的。
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
|
2月前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
23 0
Spring高手之路22——AOP切面类的封装与解析
|
2月前
|
Java Spring
Spring的AOP组件详解
该文章主要介绍了Spring AOP(面向切面编程)组件的实现原理,包括Spring AOP的基础概念、动态代理模式、AOP组件的实现以及Spring选择JDK动态代理或CGLIB动态代理的依据。
Spring的AOP组件详解
|
2月前
|
Java Spring XML
掌握面向切面编程的秘密武器:Spring AOP 让你的代码优雅转身,横切关注点再也不是难题!
【8月更文挑战第31天】面向切面编程(AOP)通过切面封装横切关注点,如日志记录、事务管理等,使业务逻辑更清晰。Spring AOP提供强大工具,无需在业务代码中硬编码这些功能。本文将深入探讨Spring AOP的概念、工作原理及实际应用,展示如何通过基于注解的配置创建切面,优化代码结构并提高可维护性。通过示例说明如何定义切面类、通知方法及其应用时机,实现方法调用前后的日志记录,展示AOP在分离关注点和添加新功能方面的优势。
38 0
|
2月前
|
缓存 安全 Java
Spring AOP 中两种代理类型的限制
【8月更文挑战第22天】
16 0
|
2月前
|
Java Spring
|
2月前
|
XML Java 数据库
Spring5入门到实战------10、操作术语解释--Aspectj注解开发实例。AOP切面编程的实际应用
这篇文章是Spring5框架的实战教程,详细解释了AOP的关键术语,包括连接点、切入点、通知、切面,并展示了如何使用AspectJ注解来开发AOP实例,包括切入点表达式的编写、增强方法的配置、代理对象的创建和优先级设置,以及如何通过注解方式实现完全的AOP配置。
下一篇
无影云桌面