| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> Spring AOP概念 -> 正文阅读 |
|
[Java知识库]Spring AOP概念 |
? 是一种动态编译期增强性AOP的实现 与IOC进行整合,不是全面的切面框架 与动态代理相辅相成 有两种实现:基于jdk动态代理、cglib Spring AOP与AspectJ区别 Spring的AOP是基于动态代理的,动态增强目标对象,而AspectJ是静态编译时增强,需要使用自己的编译器来编译,还需要织入器 使用AspectJ编写的java代码无法直接使用javac编译,必须使用AspectJ增强的ajc增强编译器才可以通过编译,写法不符合原生Java的语法;而Spring AOP是符合Java语法的,也不需要指定编译器去编译,一切都由Spring 处理。 JDK动态代理与Cglib的区别 jdk的动态代理需要实现接口 InvocationHandler cglib无需实现接口,使用字节码技术去修改class文件使继承 spring默认使用jdk动态代理,如果没有实现接口会使用cglib 使用步骤 定义业务组件 定义切点(重点) 定义增强处理方法(切面方法) 依赖 jar包依赖,除此以外还有spring依赖 ? aspectjweaver.jar aspectjrt.jar aspectj.jar aopalliance.jar maven依赖 ? ? ? <dependencies> ? ? ? ? <!-- 有此依赖会远程下载其它相关依赖 --> ? ? ? ? <dependency> ? ? ? ? ? ? <groupId>org.springframework</groupId> ? ? ? ? ? ? <artifactId>spring-context</artifactId> ? ? ? ? ? ? <version>4.2.9.RELEASE</version> ? ? ? ? </dependency> ? ? ? ? <!-- aspectJ AOP 织入器 --> ? ? ? ? <dependency> ? ? ? ? ? ? <groupId>org.aspectj</groupId> ? ? ? ? ? ? <artifactId>aspectjweaver</artifactId> ? ? ? ? ? ? <version>1.8.9</version> ? ? ? ? </dependency> ? ? ? </dependencies> 注解方式开发 扫描Aspect增强的类 <context:component-scan base-package=""> ? ? <context:include-filter type="annotation" ? ? ? ? expression="org.aspectj.lang.annotation.Aspect"/> </context:component-scan> 开启@AspectJ支持 <aop:aspectj-autoproxy/> 使用@AspectJ注解来标记一个切面类(spring不会将切面注册为Bean也不会增强,但是需要扫描) 使用其它注解进行开发(如下) 常用注解的使用 @Before:在切点方法前执行 在增强的方法上@Before("execution(* 包名.*.*(..))") 上述表达式可使用pointcut或切入表达式,效果一致,之后不再赘述 切点方法没有形参与返回值 示例代码 ? @Aspect public class AuthAspect { ? ?? ? ? //定义切点 ? ? @Pointcut("execution(* com.cnblogs.hellxz.service.*.*(..))") ? ? public void pointCut() {} ? ?? ? ? //前置处理 ? ? @Before("pointCut()") ? ? public void auth() { ? ? ? ? System.out.println("模拟权限检查……"); ? ? } } @After:在切点方法后执行 用法同@Before @Around:在切点方法外环绕执行 在增强的方法上@Around("execution(* 包名.*(..))")或使用切点@Around("pointcut()") 接收参数类型为ProceedingJoinPoint,必须有这个参数在切面方法的入参第一位 返回值为Object 需要执行ProceedingJoinPoint对象的proceed方法,在这个方法前与后面做环绕处理,可以决定何时执行与完全阻止方法的执行 返回proceed方法的返回值 @Around相当于@Before和@AfterReturning功能的总和 可以改变方法参数,在proceed方法执行的时候可以传入Object[]对象作为参数,作为目标方法的实参使用。 如果传入Object[]参数与方法入参数量不同或类型不同,会抛出异常 通过改变proceed()的返回值来修改目标方法的返回值 示例代码 ? @Aspect public class TxAspect { ? ?? ? ? //环绕处理 ? ? @Around("execution(* com.cnblogs.hellxz.service.*.*(..))") ? ? Object auth(ProceedingJoinPoint point) { ? ? ? ?? ? ? ? ? Object object = null; ? ? ? ? try { ? ? ? ? ? ? System.out.println("事务开启……"); ? ? ? ? ? ? //放行 ? ? ? ? ? ? object = point.proceed(); ? ? ? ? ? ? System.out.println("事务关闭……"); ? ? ? ? } catch (Throwable e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? ? ?? ? ? ? ? return object; ? ? } } @AfterRetruning: 在方法返回之前,获取返回值并进行记录操作 和上边的方法不同的地方是该注解除了切点,还有一个返回值的对象名 不同的两个注解参数:returning与pointcut,其中pointcut参数可以为切面表达式,也可为切点 returning定义的参数名作为切面方法的入参名,类型可以指定。如果切面方法入参类型指定Object则无限制,如果为其它类型,则当且仅当目标方法返回相同类型时才会进入切面方法,否则不会 还有一个默认的value参数,如果指定了pointcut则会覆盖value的值 与@After类似,但@AfterReturning只有方法成功完成才会被织入,而@After不管结果如何都会被织入 虽然可以拿到返回值,但无法改变返回值 ? 示例代码 ? @Aspect public class AfterReturningAspect { ? ? ? @AfterReturning(returning="rvt", ? ? ? ? ? ? pointcut = "execution(* com.cnblogs.hellxz.service.*.*(..))") ? ? //声明rvt时指定的类型会限定目标方法的返回值类型,必须返回指定类型或者没有返回值 ? ? //rvt类型为Object则是不对返回值做限制 ? ? public void log(Object rvt) { ? ? ? ? System.out.println("获取目标返回值:"+ rvt); ? ? ? ? System.out.println("假装在记录日志……"); ? ? } ? ?? ? ? /** ? ? ?* 这个方法可以看出如果目标方法的返回值类型与切面入参的类型相同才会执行此切面方法 ? ? ?* @param itr ? ? ?*/ ? ? @AfterReturning(returning="itr",? ? ? ? ? ? ? pointcut="execution(* com.cnblogs.hellxz.service.*.*(..))") ? ? public void test(Integer itr) { ? ? ? ? System.out.println("故意捣乱……:"+ itr); ? ? } } @AfterThrowing: 在异常抛出前进行处理,比如记录错误日志 与@AfterReturning类似,同样有一个切点和一个定义参数名的参数——throwing 同样可以通过切面方法的入参进行限制切面方法的执行,e.g. 只打印IOException类型的异常, 完全不限制可以使用Throwable类型 pointcut使用同@AfterReturning 还有一个默认的value参数,如果指定了pointcut则会覆盖value的值 如果目标方法中的异常被try catch块捕获,此时异常完全被catch块处理,如果没有另外抛出异常,那么还是会正常运行,不会进入AfterThrowing切面方法 示例代码 ? @Aspect public class AfterThrowingAspect { ? ? ? @Pointcut("execution(* com.cnblogs.hellxz.test.*.*(..))") ? ? public void pointcut() {} ? ?? ? ? /** ? ? ?* 如果抛出异常在切面中的几个异常类型都满足,那么这几个切面方法都会执行 ? ? ?*/ ? ? @AfterThrowing(throwing="ex1",? ? ? ? ? ? ? pointcut="pointcut()") ? ? //无论异常还是错误都会记录 ? ? //不捕捉错误可以使用Exception ? ? public void throwing(Throwable ex1) { ? ? ? ? System.out.println("出现异常:"+ex1); ? ? } ? ?? ? ? @AfterThrowing(throwing="ex",? ? ? ? ? ? ? pointcut="pointcut()") ? ? //只管IOException的抛出 ? ? public void throwing2(IOException ex) { ? ? ? ? System.out.println("出现IO异常: "+ex); ? ? } } pointcut定义的切点方法在@Before/@After/@Around需要写在双引号中,e.g. @Before("pointCut()") ? JoinPoint的概念与方法说明 概念 顾名思义,连接点,织入增强处理的连接点 程序运行时的目标方法的信息都会封装到这个连接点对象中 此连接点只读 方法说明 Object[] getArgs():返回执行目标方法时的参数 Signature getSignature():返回被增强方法的相关信息,e.g 方法名 etc Object getTarget():返回被织入增强处理的目标对象 Object getThis():返回AOP框架目标对象生成的代理对象 使用 在@Before/@After/@AfterReturning/@AfterThrowing所修饰的切面方法的参数列表中加入JoinPoint对象,可以使用这个对象获得整个增强处理中的所有细节 此方法不适用于@Around, 其可用ProceedingJoinPoint作为连接点 ProceedingJoinPoint的概念与方法说明 概念 是JoinPoint的子类 与JoinPoint概念基本相同,区别在于是可修改的 使用@ ? |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 11:56:11- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |