一、开启注解支持

1、概述

1、Spring AOP如同IoC一样支持基于XML和基于注解两种配置方式,基于注解所需的依赖和基于XML所需的依赖一致,其中spring-context包含了Spring IoC、Spring AOP等核心依赖,而aspectjweaver则是AspectJ框架的依赖,Spring使用该依赖来解析AspectJ的切入点表达式语法,以及AOP的注解支持。
2、开启AOP注解支持的方式:

2、使用XML方式的配置

1、加入aop命名空间,使用<aop:aspectj-autoproxy />标签即可,Spring将会查找被@Aspect注解标注的Bean,这表明它是一个切面Bean,然后就会进行AOP的自动配置。
2、属性说明:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--开启注解自动配置--><aop:aspectj-autoproxy/>
</beans>

3、使用Java方式的配置

1、AOP的注解支持同样可以使用Java配置方式开启,从而彻底舍弃XML配置文件。
2、配置类上添加@EnableAspectJAutoProxy,该注解用于开启Spring AOP的注解自动配置支持。
3、属性说明:
/*** @Date: 2023/2/11* 开启AOP注解支持配置类* @Configuration注解:表示该类为一个配置类* @ComponentScan注解:用于扫描包上的注解将组件加载到IoC容器中*/
@Configuration
@ComponentScan("com.itan.aop.*")
@EnableAspectJAutoProxy
public class AopConfig {}

二、切面相关注解

1、@Aspect注解

1、@Aspect注解对应着XML配置中的<aop:aspect />标签,被该注解标注的类,会被当做切面类并且用于自动配置Spring AOP。如果类仅仅只标注了该注解,那么是不会被Spring组件扫描工具自动扫描到的,并且不会加入到IoC容器中,因此还需要搭配组件注册相关的注解一起使用(如:@Component)
2、切面类和普通类一样,可以有自己的方法和字段,还可以包含切入点(pointcut)、通知(advice)、声明(introduction),这些都是通过方法来绑定的。
3、切面类本身是不能成为其他切面通知的目标类,类上面标注了@Aspect注解之后,该类的Bean将从AOP自动配置Bean中排除,因此切面类里面的方法是不能被代理的。

2、@Pointcut注解

1、@Pointcut注解对应着XML配置中的<aop:pointcut />标签,用来定义一个切入点,在匹配的情况下执行通知,切入点表达式的语法都是一样的,请参考切入点声明规则。
2、@Pointcut注解标注在一个切面类的方法上,方法名就是该切入点的名字,在通知中通过名字引用该切入点(XXX(),要带上括号),也可以将多个切入点组合成一个新的切入点(可以使用&&、||、!等运算符连接起来),XML配置中不具备该组合方式

3、通知相关注解

1、advice通知同样可以使用注解声明,并且绑定到一个方法上,一共有五种通知注解,分别和XML中的五中通知标签一一对应。
2、五种通知注解:
/*** @Date: 2023/2/11* 切面类* @Aspect:用于定义该类为一个切面类* @Component:将组件注册到IoC容器中,否则单单使用@Aspect是不会被组件扫描注解检测到的*/
@Aspect
@Component
public class AnnoAspect {/*** 切入点,该切入点匹配service包下所有类所有方法*/@Pointcut("execution(* com.itan.aop.service..*.*(..))")public void pointCut() {}/*** 前置通知*/@Before(value = "pointCut()")public void before() {System.out.println("前置通知");}/*** 异常通知*/@AfterThrowing(value = "pointCut()", throwing = "e")public void afterThrowing(Exception e) {System.out.println("异常通知,异常为:" + e.getMessage());}/*** 后置通知*/@AfterReturning(value = "pointCut()", returning = "result")public void afterReturning(Object result) {System.out.println("后置通知,返回值为:" + result);}/*** 最终通知*/@After(value = "pointCut()")public void afterFinally() {System.out.println("最终通知");}/*** 环绕通知* 一定要有ProceedingJoinPoint类型的参数*/@Around(value = "pointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {System.out.println("环绕通知 --- 进入方法");Object[] args = point.getArgs();System.out.println("外部传入的参数:" + Arrays.toString(args));System.out.println(point.toString());System.out.println(point.toShortString());System.out.println(point.toLongString());System.out.println(point.getThis());System.out.println(point.getTarget());System.out.println(point.getSignature());System.out.println(point.getSourceLocation());System.out.println(point.getKind());System.out.println(point.getStaticPart());// proceed方法表示调用切入点方法,否则方法不会执行,args表示参数,proceed就是切入点方法的返回值Object proceed = point.proceed(args);System.out.println("环绕通知 --- 退出方法");return proceed;}
}
/*** @Date: 2023/2/11* 目标接口实现类*/
@Service
public class CalculateServiceImpl implements CalculateService {public Integer add(int i, int j) {return i + j;}public int sub(int i, int j) {return i + j;}public int multiply(int i, int j) {return i * j;}public double divide(int i, int j) {return i / j;}
}
@Test
public void test04() {// 通过配置文件创建容器对象ApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);CalculateService calc = context.getBean(CalculateService.class);System.out.println(calc.getClass());calc.add(2,3);
}
/*** 运行结果:可以看到默认情况下使用JDK代理:class com.sun.proxy.$Proxy28* class com.sun.proxy.$Proxy28* 环绕通知 --- 进入方法* 外部传入的参数:[2, 3]* execution(Integer com.itan.aop.service.CalculateService.add(int,int))* execution(CalculateService.add(..))* execution(public abstract java.lang.Integer com.itan.aop.service.CalculateService.add(int,int))* com.itan.aop.service.impl.CalculateServiceImpl@3e6f3f28* com.itan.aop.service.impl.CalculateServiceImpl@3e6f3f28* Integer com.itan.aop.service.CalculateService.add(int,int)* org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@7357a011* method-execution* execution(Integer com.itan.aop.service.CalculateService.add(int,int))* 前置通知* 后置通知,返回值为:5* 最终通知* 环绕通知 --- 退出方法*/

4、通知顺序

1、当同一个连接点方法中绑定了多个同一个类型的通知时,有时需要指定通知的执行顺序,在XML中通过<aop:aspect />切面标签中的order属性指定执行通知顺序,注解配置中也能实现通知执行顺序。
2、实现方式:
  • 通知类实现Ordered接口
  • 通知类标注@Order注解
  • 提示:未设置order值时,默认值为Integer.MAX_VALUE;值越小的切面,其内部的前置通知越先执行,后置通知越后执行。
/*** @Date: 2023/2/11* 通过@Order注解方式设置顺序*/
@Aspect
@Component
@Order(Integer.MAX_VALUE - 2)
public class AnnoOrderAspect1 {/*** 切入点,该切入点匹配service包下所有类所有方法*/@Pointcut("execution(* com.itan.aop.service..*.multiply(..))")public void pointCut() {}/*** 前置通知*/@Before(value = "pointCut()")public void before() {System.out.println("AnnoOrderAspect1前置通知");}/*** 后置通知*/@AfterReturning(value = "pointCut()", returning = "result")public void afterReturning(Object result) {System.out.println("AnnoOrderAspect1后置通知,返回值为:" + result);}/*** 最终通知*/@After(value = "pointCut()")public void afterFinally() {System.out.println("AnnoOrderAspect1最终通知");}
}
/*** @Date: 2023/2/11* 通过实现Ordered接口方式设置顺序*/
@Aspect
@Component
public class AnnoOrderAspect2 implements Ordered {/*** 切入点,该切入点匹配service包下所有类所有方法*/@Pointcut("execution(* com.itan.aop.service..*.multiply(..))")public void pointCut() {}/*** 前置通知*/@Before(value = "pointCut()")public void before() {System.out.println("AnnoOrderAspect2前置通知");}/*** 后置通知*/@AfterReturning(value = "pointCut()", returning = "result")public void afterReturning(Object result) {System.out.println("AnnoOrderAspect2后置通知,返回值为:" + result);}/*** 最终通知*/@After(value = "pointCut()")public void afterFinally() {System.out.println("AnnoOrderAspect2最终通知");}/*** 获取顺序值* @return*/@Overridepublic int getOrder() {return Integer.MAX_VALUE - 1;}
}
@Test
public void test05() {// 通过配置文件创建容器对象ApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);CalculateService calc = context.getBean(CalculateService.class);System.out.println(calc.getClass());calc.multiply(2,3);
}
/*** 运行结果:值越小的切面的前置通知越先执行,后置通知越后执行* AnnoOrderAspect1前置通知* AnnoOrderAspect2前置通知* AnnoOrderAspect2后置通知,返回值为:6* AnnoOrderAspect2最终通知* AnnoOrderAspect1后置通知,返回值为:6* AnnoOrderAspect1最终通知*/

5、基于注解的AOP配置相关推荐

  1. 基于注解的 AOP 配置

    基于注解的 AOP 配置 bean.xml <?xml version="1.0" encoding="UTF-8"?> <beans xml ...

  2. Spring基于注解的AOP配置

    pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...

  3. java学习day40(Spring)spring中的aop和基于XML以及注解的AOP配置

    第1章 AOP 的相关概念[理解] 1.1AOP 概述 1.1.1 什么是 AOP AOP :全称是 Aspect Oriented Programming 即:面向切面编程. 简单的说它就是把我们程 ...

  4. 基于注解的 IOC 配置

    基于注解的 IOC 配置 学习基于注解的 IoC 配置,大家脑海里首先得有一个认知,即注解配置和 xml 配置要实现的功能都是一样 的,都是要降低程序间的耦合.只是配置的形式不一样. 关于实际的开发中 ...

  5. spring中基于XML的AOP配置步骤

    spring中基于XML的AOP配置步骤 IAccountService.java package com.itheima.service;/*** 账户的业务层接口*/ public interfa ...

  6. 基于注解的 IOC 配置——创建对象(Component、Controller、Service、Repository)注入数据(Autowired、Qualifier、Resource、Value)

    基于注解的 IOC 配置 注解配置和 xml 配置要实现的功能都是一样的,都是要降低程序间的耦合.只是配置的形式不一样. XML的配置: 用于创建对象的 用于注入数据的 用于改变作用范围的 生命周期相 ...

  7. spring 基于注解的控制器配置

    http://ttaale.iteye.com/blog/787586 spring 基于注解的控制器配置 博客分类: spring SpringBeanServletMVCWeb 13.12. 基于 ...

  8. 缓存初解(五)---SpringMVC基于注解的缓存配置--web应用实例

    之前为大家介绍了如何使用spring注解来进行缓存配置 (EHCache 和 OSCache)的简单的例子,详见 Spring基于注解的缓存配置--EHCache AND OSCache 现在介绍一下 ...

  9. 基于XML的AOP配置

    创建spring的配置文件并导入约束 此处要导入aop的约束 <?xml version="1.0" encoding="UTF-8"?> < ...

最新文章

  1. 日本政府用AI分配对象了!给你分一个的话,敢不敢要?
  2. 自定义 checkbox 新玩法 ?
  3. 【收藏】Hadoop解决Could not locate executable null\bin\winutils.exe in the Hadoop binaries.问题
  4. android ble 实现自动连接,Android:自动重新连接BLE设备
  5. Oracle11g修改实例名和数据库名
  6. 【MyBatis框架】mapper配置文件-关于动态sql
  7. android 判断服务是否正在运行,Android 判断某个服务(service)是否运行
  8. Sharepoint学习笔记—ECM系列--从.CSV文件导入术语集(Term Sets)
  9. iOS 警告收录及科学快速的消除方法
  10. 正确理解TensorFlow中的logits
  11. Atitit.列表页面and条件查询的实现最佳实践(1)------设置查询条件and提交查询and返回json数据
  12. win mysql 命令行提示_数据分析进阶——mysql基本语句
  13. 一些iOS面试题答案
  14. JAVA实现微信支付功能
  15. 计算机组成原理00h,计算机组成原理 (2).doc
  16. chi2inv函数 matlab_matlab函数列表(A~Z)【转】
  17. 一个屌丝程序员的青春(三七九)
  18. springBoot引入mysql数据库连接:errorCode1045,state28000的解决办法
  19. 编程示例:jsp在数据库中的编程
  20. spss基础-5.10

热门文章

  1. 阿里云国际站的对象存储oss与自建存储的区别
  2. 【只摘金句】Linux开发模式带给我们的思考
  3. Android 系统名字、版本、API level的对应关系
  4. 没有Console线,又不知道自己通过哪个IP连接到路由器,怎么办?
  5. [BJOI2019]勘破神机(斯特林数,数论)
  6. 基础C语言知识串串香10☞数组字符串结构体联合体枚举
  7. 你的饿了么订单又超时啦!
  8. 数据库系统概念 - 数据模型,关系模型,关系,候选码,主码,外码
  9. 十二星座分手时会怎么说?
  10. 哪个软件测试手机电池续航好,6款手机电池续航测试排名:iPhone12mini险些垫底,第1名是小米10...