• SpringAOP——概念与简单实现


    参考官网5-6+百度翻译...

    一、概念

    1、OOP与AOP

    面向切面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP)。

    OOP:面向对象编程,关键单元是对象,面向的是一个个对象。

    AOP:面向切面编程,关键单元是切面,面向的是一个个切面。切面关注点可能是多个不同类型的对象的相同点,也就是说切面可以跨域多个类型和对象。

    OOP与AOP两种不同的编程思想,为什么说AOP是OOP的补充呢?将切面视为一个对象,面向切面也就是面向对象。(面向对象就是吊,跟马哲似的。)

    2、SpringIOC与SpringAOP

    Spring两大核心组件:SpringIOC与SpringAOP,SpringIOC是OOP思想实现的框架组件,SpringAOP则是AOP思想实现框架组件。

    经过上面理解先猜想一下:

    ① SpringAOP的一个切面的关注点可以横跨SpringIOC容器里多个对象。

    ② SpringAOP的切面本身也是一个对象,会放入到SpringIOC容器中。

    3、AspectJ与SpringAOP

    AspectJ与SpringAOP都是AOP思想实现的框架。区别在于:

    AspectJ:编译期通过字节码技术修改class文件实现切面,运行期内存中仅有一个对象。

    SpringAOP:编译器不修改class文件,运行期运用动态代理生成代理类完成切面。内存中会有两个对象(target object & proxy object)

    AspectJ的一些切入点、表达式解析简单,SpringAOP吸取了这一优点,使用AspectJ的库来解释与AspectJ 5相同的注释和表达式(例如pointcut的匹配表达式)。因此项目中使用SpringAOP时,会依赖AspectJ框架的jar包——aspectJ.jar,但是这个jar包仅仅是解析匹配作用,AOP运行时仍然是纯Spring AOP(代理实现),并且不依赖于AspectJ编译器或编织器,总结:SpringAOP=AspectJ的注解表达式解析+SpringAOP动态代理实现;SpringAOP与AspectJ框架语法大致相同。

    3、术语

    AOP术语

    AspectJ:切面

    Join point:程序执行过程中的一个点,切面关注点包含的一个对象。

    Advice:切面在关注点处采取的操作

    pointcut:比Join point大的概念,切面关注点包含的所有对象。advice与pointcut表达式关联,并在与该切入点匹配的任何Join point处运行(例如,执行具有特定名称的方法)。

    pointcut表达式匹配的join point的概念是AOP的核心,Spring默认使用AspectJ切入点表达语言

    introduction:给类型声明其他方法或字段。Spring AOP中允许向任何切入关键点有关的对象引入新的接口(和相应的实现)。例如,您可以使用introduction 使Bean实现 IsModified接口,以简化缓存。

    Target object:一个或多个切面Advice的对象。也称为“advised object”。由于Spring AOP是使用运行时代理实现的,因此该对象始终是代理对象。

    AOP proxy:由AOP框架创建的一个代理,用于执行切面的协定(advice方法执行等)。在Spring Framework中,AOP代理是JDK动态代理或CGLIB代

    Weaving:将切面与其他类型或对象链接以创建代理对象。这可以在编译时(例如,使用AspectJ编译器),加载时或在运行时完成。Spring AOP在运行时执行编织

    SpringAOP拓展术语

    before advice:在连接点之前运行的advice,但是它不能阻止执行流程继续进行到join point(除非它引发异常)。

    after returning advice:在join point正常完成之后要运行的advice(例如,如果方法返回而没有引发异常)

    after throwing advice:如果方法因抛出异常而退出,则执行advice

    after (finally) advice:无论join point退出的方式如何(正常或特殊返回),均应执行advice

    around advice:围绕jion point的advice,例如方法调用。这是最有力的advice。around advice可以在方法调用之前和之后执行自定义行为。它还负责选择是返回join point还是通过返回其自身的返回值或引发异常来捷径建议的方法执行

    生涩难懂的概念:理解起来真是麻烦,自己建模成一个数学几何问题理解一下。方法调用是纵向的,将线程执行视为一条垂线。

     

    4、springAOP实现

    Spring AOP默认将标准JDK动态代理用于AOP代理,也可以使用CGLIB代理。

    如果要代理的目标对象实现至少一个接口,则使用JDK动态代理。代理了由目标类型实现的所有接口。如果目标对象未实现任何接口,则将创建CGLIB代理(CGLIB继承实现代理所以方法不能被final修饰)

    public interface Xxable {
        void xx();
    }
    
    @Component
    public class A implements Xxable{
        @Override
        public void xx() {
            System.out.println("I am A xx");
        }
    }
    
    @Component
    public class B{
    
        public void xx() {
            System.out.println("I am b xx");
        }
    }
    
    @Component//切面必须放到IOC容器中
    @org.aspectj.lang.annotation.Aspect//aspecjweaver.jar SpringAOP的注解是AspectJ解析的
    public class Aspect {
        @Pointcut("execution(* xx())")
        public void pointCut(){
    
        }
    
        @Before("pointCut()")//aspecjweaver.jar SpringAOP的表达式也是AspectJ解析的
        public void beforeAdvice(){
            System.out.println("before advice");
        }
    
        @After("pointCut()")
        public void afterAdvice(){
            System.out.println("after advice");
        }
    }
    
    @Configuration
    @EnableAutoConfiguration
    @EnableAspectJAutoProxy//启用SpringAOP
    public class Main {
    
        public static void main(String[] args){
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            context.scan("com.app.aop");
            context.refresh();
            A a = (A)context.getBean("a");
            B b = (B)context.getBean("b");
            a.xx();
            b.xx();
            System.out.println(a.getClass().getName());//本来只是想随便打印一下具体类型
            System.out.println(b.getClass().getName());//结果发现spring5.x默认jdk动态代理,但是springboot2.x默认cglib代理
        }
    }

    简单步骤:

    ① 需要启用SpringAOP支持,@EnableAspectJAutoProxy

    ② 声明一个aspect切面,必须且切面也是一个对象,需要注入到容器中。@Aspect & @Component

    ③ 声明关注点@pointcut

    ④ 声明advice

    5、用上面例子验证Advice执行

    //无exception
    around before advice
    before advice
    I am A xx
    around after advice
    after advice
    AfterReturning advice
    //有exception 不会执行aroud after 
    around before advice
    before advice
    I am A xx
    after advice
    AfterThrowing advice
    exception

    6、pointcut表达式解析

    • execution:模糊匹配。用于匹配方法执行的join points。这是使用Spring AOP时要使用的主要切入点指示符。

    • within:包或类型匹配。将匹配限制为某些类型内的join points(使用Spring AOP时,在匹配类型内声明的方法的执行)。

    • this:指定代理对象(proxy object)。限制匹配到join points(使用Spring AOP时方法的执行)的匹配,其中bean引用(Spring AOP代理)是给定类型的实例。

    • target:指定目标对象(target object)。在目标对象(代理的应用程序对象)是给定类型的实例的情况下,将匹配限制为join points(使用Spring AOP时方法的执行)。

    • args:指定方法参数。在参数为给定类型的实例的情况下,将匹配限制为join points(使用Spring AOP时方法的执行)。

    • @target:在执行对象的类具有给定类型的注释的情况下,将匹配限制为join points(使用Spring AOP时方法的执行)。

    • @args:限制匹配的join points(使用Spring AOP时方法的执行),其中传递的实际参数的运行时类型具有给定类型的注释。

    • @within:将匹配限制为具有给定注释的类型内的join points(使用Spring AOP时,使用给定注释的类型中声明的方法的执行)。

    • @annotation:匹配注解(自定义注解的良好使用)。将匹配限制在join points的主题(Spring AOP中正在执行的方法)具有给定注释的连接点上。

    官方给出的表达式格式及列举的常用pointcut表达式:

    //modifiers-pattern? 方法访问修饰符public private等匹配
    //ret-type-pattern 方法返回类型匹配
    //declaring-type-pattern  方法声明类型匹配
    //name-pattern(param-pattern) 方法名称匹配
    // thows-pattern 方法声明异常throws匹配
    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
    
    //常用表达式
    //所有public 方法
    execution(public * *(..))
    //所有set开头的方法
    execution(* set*(..))
    //AccountService接口定义的所有方法
    execution(* com.xyz.service.AccountService.*(..))
    //service包下的所有方法
    execution(* com.xyz.service.*.*(..))
    //service包或其子包的所有方法
    execution(* com.xyz.service..*.*(..))
    //service包下的所有方法
    within(com.xyz.service.*)
    //service包或其子包的所有方法
    within(com.xyz.service..*)
    //代理对象实现AccountService接口的所有方法
    this(com.xyz.service.AccountService)
    //目标对象实现AccountSerivce接口的所有方法
    target(com.xyz.service.AccountService)
    //采用单个参数的所有方法
    args(java.io.Serializable)
    //目标对象的声明类型带有@Transactional注解的所有方法
    @target(org.springframework.transaction.annotation.Transactional)
    //目标对象的声明类型带有@Transactional注解的所有方法
    @within(org.springframework.transaction.annotation.Transactional)
    //带有@Transactional注解的所有方法
    @annotation(org.springframework.transaction.annotation.Transactional)
    //任何采用单个参数的方法,且参数类型被@Classified注解
    @args(com.xyz.security.Classified)
    //beanName=tradeService的bean的所有方法
    bean(tradeService)
    //beanName=*Service的bean的所有方法
    bean(*Service)
  • 相关阅读:
    【leetcode】1020. Partition Array Into Three Parts With Equal Sum
    【leetcode】572. Subtree of Another Tree
    【leetcode】123. Best Time to Buy and Sell Stock III
    【leetcode】309. Best Time to Buy and Sell Stock with Cooldown
    【leetcode】714. Best Time to Buy and Sell Stock with Transaction Fee
    【leetcode】467. Unique Substrings in Wraparound String
    【leetcode】823. Binary Trees With Factors
    【leetcode】143. Reorder List
    【leetcode】1014. Capacity To Ship Packages Within D Days
    【leetcode】1013. Pairs of Songs With Total Durations Divisible by 60
  • 原文地址:https://www.cnblogs.com/wqff-biubiu/p/12391875.html
Copyright © 2020-2023  润新知