Spring AOP应用

 切面通知应用增强

1. 通知类型

​ 在基于Spring AOP编程的过程中,基于AspectJ框架标准,Spring中定义了五种类型的通知(通知描述的是一种扩展业务),它们分别是:

  • 前置通知 (@Before)
  • 返回通知 (@AfterReturning)
  • 异常通知 (@AfterThrowing)
  • 后置通知 (@After)
  • 环绕通知 (@Around) : 重点掌握(优先级最高)
1.2 通知执行顺序及实践

代码实践如下:

@Component
@Aspect
public class SysTimeAspect {
        @Pointcut("bean(productController)")
        public void doTime(){}
        
        @Before("doTime()")
        public void doBefore(JoinPoint jp){
                System.out.println("time doBefore()");
        }

        @After("doTime()")
        public void doAfter(){
                System.out.println("time doAfter()");
        }

        /**核心业务正常结束时执行 执行returning*/
        @AfterReturning("doTime()")
        public void doAfterReturning(){
                System.out.println("time doAfterReturning");
        }

        /**核心业务出现异常时执行 执行Throwing*/
        @AfterThrowing("doTime()")
        public void doAfterThrowing(){
                System.out.println("time doAfterThrowing");
        }

        @Around("doTime()")
        public Object doAround(ProceedingJoinPoint jp) throws Throwable{
                System.out.println("doAround.before");
				Object obj=jp.proceed();
				System.out.println("doAround.after");
				return obj;
        }
}

假如这些通知全部写到一个切面对象中,其执行顺序及过程 :

  • 正常时 : @Around –> @Before –> @AfterReturning –> @After –> @Around

  • 异常时 : @Around –> @Before –> @AfterThrowing –> @After –> @Around

说明 : 实际项目中可能不会在切面中定义所有的通知,具体定义哪些通知要结合业务进行实现。SpringBoot不同版本中通知的执行顺序以项目实际运行结果为准。

1.3切入点表达式增强

Spring中通过切入点表达式定义具体切入点,其常用AOP切入点表达式定义及说明:

image-20230130142648476

1.3.1 bean表达式(重点)

bean表达式一般应用于类级别,实现粗粒度的切入点定义,案例分析:

  • bean(“productController”) 指定一个 productController 类中所有方法
  • bean("*Controller") 指定所有后缀为 Controller 的类中所有方法

说明 : bean表达式内部的对象是由 Spring 容器管理的一个bean对象 , 表达式内部的名字应该是 Spring 容器中某个bean的name。

1.3.2 within表达式(了解)

within表达式应用于类级别,实现粗粒度的切入点表达式定义,案例分析:

  • within(“aop.controller.ProductController”) 指定当前包中这个类内部的所有方法
  • within(“aop.controller . *”) 指定当前目录下的所有类的所有方法
  • within(“aop.controller. .*”) 指定当前目录以及子目录中类的所有方法
1.3.3 execution表达式(了解)

execution表达式应用于方法级别,实现细粒度的切入点表达式定义,案例分析: 语法:execution(返回值类型 包名.类名.方法名(参数列表))。

  • execution(void aop.service.UserServiceImpl.addUser()) 匹配addUser方法
  • execution(void aop.service.PersonServiceImpl.addUser(String)) 方法参数必须为String的addUser方法
  • execution(* aop.service. .* .*(. .)) 万能配置
1.3.4 @annotation表达式(重点)

@annotaion表达式应用于方法级别,实现细粒度的切入点表达式定义,案例分析

  • @annotation(anno.RequiredLog) 匹配有此注解描述的方法
  • @annotation(anno.RequiredCache) 匹配有此注解描述的方法

说明 : @RequiredLog 为我们自己定义的注解 , 当我们使用 @RequiredLog 注解修饰业务层方法时 , 系统底层会在执行此方法时进行日志扩展操作。

1.4 @annotation表达式练习

​ 定义 Cache 相关切面 , 使用注解表达式定义切入点 , 并使用此注解对需要使用Cache的业务方法进行描述 , 代码分析如下 :

第一步 : 定义注解 @RequiredCache

/**
 * 自定义注解,一个特殊的类,所有注解都默认继承Annotation接口
 */
@Retention(RetentionPolicy.RUNTIME) //运行时有效
@Target(ElementType.METHOD) //修饰方法
public @interface RequiredCache {
}

定义注解 @ClearCache

/**
 * 自定义注解,一个特殊的类,所有注解都默认继承Annotation接口
 */
@Retention(RetentionPolicy.RUNTIME) //运行时有效
@Target(ElementType.METHOD) //修饰方法
public @interface ClearCache {
}

第二步 : 定义 CacheAspect 切面对象

@Aspect
@Component
public class CacheAspect {
           
	private Map<Object,Object> cache = new ConcurrentHashMap<>();
	
	@Pointcut("@annotation(com.cy.pj.common.annotation.RequiredCache)")
	public void doCache() {}
	
	@Pointcut("@annotation(com.cy.pj.common.annotation.ClearCache)")
	public void doClear() {}
	
    //注意,这里选用返回通知,因为只有业务代码执行成功才能执行此通知
	@AfterReturning("doClear()")
	public void doAfterReturning() {
		cache.clear();
	}
	
	@Around("doCache()")
	public Object doAround(ProceedingJoinPoint jp) throws Throwable {
		System.out.println("Get Data from Cache");
		Object result = cache.get("dataKey");
		if(result!=null) return result;
		result = jp.proceed(); //执行目标方法
		System.out.println("Put Data from Cache");
		cache.put("dataKey", result);
		return result;
	}
}

第三步 : 使用 @RequiredCache 注解对特定业务目标对象中的查询方法进行描述。

@RequiredCache
/**查询前端系统首页商品列表信息*/
@GetMapping("/product/list/index")
public List<Product> doSelectIndex(){
    return productMapper.selectIndex();
}

使用 @ClearCache 注解对特定业务目标对象中的查询方法进行描述。

@ClearCache
/**发布新商品*/
@PostMapping("/product/insert")
public void insert(@RequestBody Product product){
    product.setCreated(new Date());
    productMapper.insert(product);
}
Spring AOPSpring框架中应用AOP(面向切面编程)思想的一种方式。它使用动态代理技术来实现。默认情况下,Spring会根据被代理对象是否实现接口来选择使用JDK动态代理还是CGLIB动态代理。当被代理对象没有实现任何接口时,Spring会选择CGLIB。当被代理对象实现了接口,Spring会选择JDK官方的代理技术。但是我们也可以通过配置的方式,让Spring强制使用CGLIB动态代理。 Spring AOP的配置方式有多种,包括XML模式、XML注解模式和纯注解模式。通过这些配置方式,我们可以将AOP的切面逻辑织入到我们的业务代码中,实现各种功能,比如事务管理等。 在Spring中,事务管理是AOP的一种常见应用Spring提供了多种事务管理器的实现,例如DataSourceTransactionManager和HibernateTransactionManager等。这些事务管理器实现了Spring的事务管理器核心接口,负责提供具体的事务实现策略。我们可以根据需要选择合适的事务管理器来管理数据库操作或其他事务。同时,Spring也提供了基于注解的声明式事务配置,通过在代码中使用注解来实现事务管理。 总之,Spring AOP可以应用在各种场景中,包括但不限于事务管理。通过AOP的切面编程思想,我们可以将一些横切逻辑代码(比如事务管理、日志记录等)与业务代码解耦,提高代码的可维护性和可扩展性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Spring AOP 应用](https://blog.csdn.net/weixin_44152160/article/details/125360176)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值