Spring框架-AOP

概念

         AOP(Object-Oriented Programming)面向对象编程,允许开发者定义纵向的关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。

        AOP(Aspect-Oriented Programming),一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为 切面 Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等。

实现方式

        AOP实现的关键在于 代理模式, AOP 代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以 Spring AOP 为代表。
        ( 1) AspectJ 是静态代理的增强,所谓静态代理,就是 AOP 框架会在编译阶段生成 AOP 代理 类,因此也称为编译时增强,他会在编译阶段将 AspectJ( 切面 ) 织入到 Java 字节码中,运行的时候就是增强之后的AOP 对象。
         (2 Spring AOP 使用的动态代理,所谓的动态代理就是说 AOP 框架不会去修改字节码,而是每次 运行时在内存中临时为方法生成一个 AOP 对象,这个 AOP 对象包含了目标对象的全部方法,并且在 特定的切点做了增强处理,并回调原对象的方法。

什么是切面 Aspect

        aspect 由 pointcount advice 组成,切面是通知和切点的结合。 它既包含了横切逻辑的定义, 也包括了连接点的定义 . Spring AOP 就是负责实施切面的框架 , 它将切面所定义的横切逻辑编织到切面所指定的连接点中 . AOP 的工作重心在于如何将增强编织目标对象的连接点上 , 这里包含两个工作 :
        1. 如何通过 pointcut advice 定位到特定的 joinpoint 上.
        2. 如何在 advice 中编写切面代码 .
        可以简单地认为, 使用 @Aspect 注解的类就是切面

JDK动态代理和CGLIB动态代理的区别

Spring AOP 中的动态代理主要有两种方式, JDK 动态代理和 CGLIB 动态代理
        JDK动态代理只提供接口的代理,不支持类的代理。核心 InvocationHandler 接口和 Proxy类,InvocationHandler 通过 invoke() 方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy 利用 InvocationHandler 动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
        如果代理类没有实现 InvocationHandler 接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类。CGLIB Code Generation Library ),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP 。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为 fifinal ,那么它是无法使用CGLIB做动态代理的。
        静态代理与动态代理区别在于生成AOP 代理对象的时机不同,相对来说 AspectJ的静态代理方式具 有更好的性能,但是 AspectJ 需要特定的编译器进行处理,而 Spring AOP则无需特定的编译器处 理

Spring通知有哪些类型?

        在AOP 术语中,切面的工作被称为通知,实际上是程序执行时要通过 SpringAOP框架触发的代码段。
 
Spring 切面可以应用 5 种类型的通知:
        1. 前置通知( Before ):在目标方法被调用之前调用通知功能;
        2. 后置通知( After ):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
        3. 返回通知( After-returning ):在目标方法成功执行之后调用通知;
        4. 异常通知( After-throwing ):在目标方法抛出异常后调用通知;
        5. 环绕通知( Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

前置通知

准备一个Aspect切面类

public class MyAspects {
    //方法名可以随意
    public void before(JoinPoint joinPoint,String title){
        System.out.println("这是前置增强程序");
    }
}

添加配置

 测试程序

 后置通知

public class MyAspects {
    //方法名可以随意
    public void after(JoinPoint joinPoint,Object returnVal){
        System.out.println("这是后置增强程序");
    }
}

添加配置

         后置通知是在方法返回之后的增强程序,所以可以获取到方法的返回值。

 我们修改业务, 增加返回值

public class MyAspects {
    //方法名可以随意
    public void after(JoinPoint joinPoint,Object returnVal){
        System.out.println("这是后置增强程序");
        System.out.println("被增强方法的返回值为:"+returnVal);
    }
}

 测试程序

 环绕通知, 异常通知, 最终异常

        程序相同, 配置文件中更改方法名即可, 此处略写

使用Advisor的方式进行AOP的配置

前置通知

我们自己写一个类,实现接口MethodBeforeAdvice

public class MyBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("advisor前置通知");
    }
}

 添加配置

 环绕通知

自己写一个类,实现接口MethodBeforeAdvice

public class MyInterceptor implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("{{环绕通知开始}}");
        Object obj = invocation.proceed(); //接受返回值
        System.out.println("{{环绕通知结束}}");
        return obj; // 返回返回值
    }
}

 添加配置

 后置通知, 异常通知, 最终通知, 略

各种通知的执行顺序

        前置通知
        环绕通知开始部分
        [业务部分]
        ///有可能出现异常通知,异常出现,环绕和后置不会再执行
        环绕通知结束
        后置通知
        最终通知(无论是否有异常都必须有后置通知)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

差点资深程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值