基础框架 Spring AOP切面

╰+哭是因爲堅強的太久メ 2022-12-29 04:44 228阅读 0赞

基础框架 Spring AOP切面

一、概念

  1. 什么是aop
    AOP就是面向切面编程,就是不通过修改代码的方式,在主干功能的某个类的方法执行前后添加新的功能。
  2. 为什么要用aop
    AOP面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被称为为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理。

二、aop原理

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

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

(3)静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。

aop两种代理模式案例

三、常见术语

  1. 连接点
    类里面那些方法可以被增强,这些方法称为连接点。
  2. 切入点
    实际被真正增强的方法,称为切入点。
  3. 通知(增强)
    实际增强逻辑部分称为通知(增强)

    • 前置通知
    • 后置通知
    • 环绕通知
    • 异常通知
    • 最终通知
  4. 切面
    把通知应用到切入点的过程。

四、案例

  1. Spring框架aop操作一般都是基于AspectJ实现
    AspectJ不是spring组成部分,独立aop框架,一般AspectJ和spring框架结合使用,进行aop操作。
  2. 基于AspectJ实现aop操作方式

    • 基于xml配置文件实现
    • 基于注解实现
  3. 引入依赖
    在这里插入图片描述

  4. 切入点表达式
    (1)切入点表达式的作用:知道对哪个类的那个方法增强。
    (2)语法结构:

execution([权限修饰符] [返回类型] [类全路径] [方法名称] (参数列表))
例1:对com.spring.dao.BookDao类的add增强
execution(* com.spring.dao.BookDao.add(. .))

例2:对com.spring.dao.BookDao类的所有方法增强
execution(* com.spring.dao.BookDao.*(. .))

例3:对com.spring.dao包的所有类的所有方法增强
execution(* com.spring.dao..(. .))

  1. 验证
    aop实现的三种方式
    (1)xml配置
    (2)注解方式
    (3)AspectJ配置

    package com.spring5.aopanno;

    import org.springframework.stereotype.Component;

    / 用户 @author zrj @date 2020/12/20 * @since V1.0 /
    @Component
    public class User {

    1. /** * 定义新增方法 */
    2. public void add() {
    3. System.out.println( "【UserDao】执行add方法..." );
    4. }

    }

    package com.spring5.aopanno;

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;

    / User增强类 Component:标注bean Aspect :生成代理对象 Order:有多个不同类型的增强的时候,设置优先级 @author zrj @date 2020/12/20 @since V1.0 /
    @Component
    @Aspect
    @Order(3)
    public class UserProxy {

    1. /** * 相同切入点抽取 */
    2. @Pointcut(value = "execution(* com.spring5.aopanno.User.add(..))")
    3. public void pointDemo() {
    4. }
    5. /** * 前置通知 * * @Before注解表示作为前置通知 */
    6. @Before(value = "pointDemo()")
    7. public void before() {
    8. System.out.println( "【前置通知】Before........." );
    9. }
    10. /** * 后置通知(返回通知) */
    11. @AfterReturning(value = "execution(* com.spring5.aopanno.User.add(..))")
    12. public void afterReturning() {
    13. System.out.println( "【后置通知】AfterReturning........." );
    14. }
    15. /** * 最终通知 */
    16. @After(value = "execution(* com.spring5.aopanno.User.add(..))")
    17. public void after() {
    18. System.out.println( "【最终通知】After........." );
    19. }
    20. /** * 异常通知 */
    21. @AfterThrowing(value = "execution(* com.spring5.aopanno.User.add(..))")
    22. public void afterThrowing() {
    23. System.out.println( "【异常通知】AfterThrowing........." );
    24. }
    25. /** * 环绕通知 */
    26. @Around(value = "execution(* com.spring5.aopanno.User.add(..))")
    27. public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    28. System.out.println( "【环绕之前】Around........." );
    29. //被增强的方法执行
    30. proceedingJoinPoint.proceed();
    31. System.out.println( "【环绕之后】Around........." );
    32. }

    }

    package com.spring5.aopxml;

    / @author zrj @date 2020/12/20 * @since V1.0 /
    public class Book {

    1. public void buy() {
    2. System.out.println( "【购买方法】buy............." );
    3. }

    }

    package com.spring5.aopxml;

    import org.aspectj.lang.ProceedingJoinPoint;

    / 书增强类 @author zrj @date 2020/12/20 * @since V1.0 /
    public class BookProxy {

    1. /** * 前置通知 * * @Before注解表示作为前置通知 */
    2. public void before() {
    3. System.out.println( "【前置通知】Before........." );
    4. }
    5. /** * 后置通知(返回通知) */
    6. public void afterReturning() {
    7. System.out.println( "【后置通知】AfterReturning........." );
    8. }
    9. /** * 最终通知 */
    10. public void after() {
    11. System.out.println( "【最终通知】After........." );
    12. }
    13. /** * 异常通知 */
    14. public void afterThrowing() {
    15. System.out.println( "【异常通知】AfterThrowing........." );
    16. }
    17. /** * 环绕通知 */
    18. public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    19. System.out.println( "【环绕之前】Around........." );
    20. //被增强的方法执行
    21. proceedingJoinPoint.proceed();
    22. System.out.println( "【环绕之后】Around........." );
    23. }

    }

    package com.spring5.config;

    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;

    /* 3.注解方式实现aop操作 */
    @Configuration
    @ComponentScan(basePackages = { “com.spring5”})
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class ConfigAop {
    }

    <?xml version=”1.0” encoding=”UTF-8”?>




























    package com.spring5.aopanno;

    import com.spring5.aopxml.Book;
    import com.spring5.config.ConfigAop;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    / @author zrj @date 2020/12/20 * @since V1.0 /
    public class SpringAopTest {

    1. /** * xml配置方式操作aop */
    2. @Test
    3. public void springAopXmlTest() {
    4. System.out.println( "-----xml配置方式操作aop-----" );
    5. // 加载spring配置文件
    6. ApplicationContext context = new ClassPathXmlApplicationContext( "bean2.xml" );
    7. // 获取对象
    8. User user = context.getBean( "user", User.class );
    9. user.add();
    10. }
    11. /** * 注解方式实现aop */
    12. @Test
    13. public void springAopConfigTest() {
    14. System.out.println( "-----注解方式实现aop-----" );
    15. // 加载配置类
    16. ApplicationContext applicationContext = new AnnotationConfigApplicationContext( ConfigAop.class );
    17. // 获取对象
    18. User user = applicationContext.getBean( "user", User.class );
    19. user.add();
    20. }
    21. /** * AspectJ配置文件方式 */
    22. @Test
    23. public void springAopAspectJXmlTest() {
    24. System.out.println( "-----AspectJ配置文件方式-----" );
    25. // 加载spring配置文件
    26. ApplicationContext context = new ClassPathXmlApplicationContext( "bean2.xml" );
    27. // 获取对象
    28. Book book = context.getBean( "book", Book.class );
    29. book.buy();
    30. }

    }

发表评论

表情:
评论列表 (有 0 条评论,228人围观)

还没有评论,来说两句吧...

相关阅读