| |
|
开发:
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详解 |
1.前言spring aop是一个面向切面的编程,在自己第一遍学习的时候,感觉aop没有什么作用,但是真实接触下来,感觉spring aop还是很有用途的,感觉自己之前的想法太年轻了。 2.概念Spring 提供了两种AOP 的实现:基于注解式配置和基于XML配置,我这里主要就是介绍一下,基于注解式配置。 2.1 AOP 即 Aspect Oriented Program 面向切面编程 首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能。
周边功能在 Spring 的面向切面编程AOP思想里,即被定义为切面 在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发,然后把切面功能和核心业务功能 "编织" 在一起,这就叫AOP 2.2 AOP 的目的 AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。 2.3 AOP 当中的概念:
2.4 Spring Aop中的通知类型:
2.5 spring Aop实现的基础 spring aop实现是通过动态代理的方式实现的,动态代理避免了静态代理需要定义冗余的代理类,实现类,动态代理分为两种,第一种就是jdk 动态代理,第二种就是cglib 动态代理,aop 实现同时采用两种代理模式。 两种动态代理的区别: jdk动态代理模式 :采用反射的方式,只能对实现接口的类生成代理,具有加载速度快,执行效率低的特点。 cglib动态代理模式:采用的asm,通过字节码形式实现,是针对类实现代理,具有加载速度慢,执行效率高的特点。 2.6 基于AspectJ实现基础上需要连接的几个内置注解 execution函数用于匹配方法执行的连接点,语法为: execution(方法修饰符(可选) 返回类型 方法名(参数) 异常模式(可选)) 参数部分允许使用通配符: * 匹配任意字符,但只能匹配一个元素 .. 匹配任意字符,可以匹配任意多个元素(零到若干个都可以),必须和*联合使用 "execution(public * com.qli.controller.TestController.*(..))" @Pointcut(value = "@annotation(com.qli.config.RequestLog)")任何方法使用RequestLog注解都会触发该切面,进入切点 3.实现具体的案例,在spring boot中实现spring aop,包含的内容有通过aop实现自定义注解,听起来就很高大上,其实懂了之后,感觉就那样,不过在新入门的程序员面前还是可以装起来的,还有就是多个切面的时候的执行顺序 3.1导入依赖 <!--引入父依赖 ? ? ? ? 当前工程 继承 父类工程 spring-boot-starter-parent pom ? --> ? <parent> ? ? ? <groupId>org.springframework.boot</groupId> ? ? ? <artifactId>spring-boot-starter-parent</artifactId> ? ? ? <version>2.1.3.RELEASE</version> ? ? ? <relativePath/> ? </parent> ? ? <properties> ? ? ? <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> ? ? ? <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> ? ? ? <java.version>1.8</java.version> ? </properties> ? ? ? <dependencies> ? ? <!-- web相关依赖--> ? <dependency> ? ? ? <groupId>org.springframework.boot</groupId> ? ? ? <artifactId>spring-boot-starter-web</artifactId> ? ? </dependency> ? ? <dependency> ? ? ? <groupId>org.springframework.boot</groupId> ? ? ? <artifactId>spring-boot-starter-test</artifactId> ? </dependency> ? ? ? ? <dependency> ? ? ? ? ? <groupId>org.springframework.boot</groupId> ? ? ? ? ? <artifactId>spring-boot-starter-aop</artifactId> ? ? ? </dependency> ? </dependencies> 3.2创建切面 package com.qli.config; ? import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; ? import javax.servlet.http.HttpServletRequest; import java.util.Arrays; ? @Aspect @Component @Order(2) public class LogAspect { ? @Pointcut("execution(public * com.qli.controller.TestController.*(..))") ? public void webLog(){} ? ? @Before("webLog()") ? public void deBefore(JoinPoint joinPoint) throws Throwable { ? ? ? // 接收到请求,记录请求内容 ? ? ? ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); ? ? ? HttpServletRequest request = attributes.getRequest(); ? ? ? // 记录下请求内容 ? ? ? System.out.println("URL : " + request.getRequestURL().toString()); ? ? ? System.out.println("HTTP_METHOD : " + request.getMethod()); ? ? ? System.out.println("IP : " + request.getRemoteAddr()); ? ? ? System.out.println("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); ? ? ? System.out.println("ARGS : " + Arrays.toString(joinPoint.getArgs())); ? ? } ? ? @AfterReturning(returning = "ret", pointcut = "webLog()") ? public void doAfterReturning(Object ret) throws Throwable { ? ? ? // 处理完请求,返回内容 ? ? ? System.out.println("方法的返回值 : " + ret); ? } ? ? //后置异常通知 ? @AfterThrowing("webLog()") ? public void throwss(JoinPoint jp){ ? ? ? System.out.println("方法异常时执行....."); ? } ? ? //后置最终通知,final增强,不管是抛出异常或者正常退出都会执行 ? @After("webLog()") ? public void after(JoinPoint jp){ ? ? ? System.out.println("方法最后执行....."); ? } ? ? //环绕通知,环绕增强,相当于MethodInterceptor ? @Around("webLog()") ? public Object arround(ProceedingJoinPoint pjp) { ? ? ? System.out.println("方法环绕start....."); ? ? ? try { ? ? ? ? ? Object o = pjp.proceed(); ? ? ? ? ? System.out.println("方法环绕proceed,结果是 :" + o); ? ? ? ? ? return o; ? ? ? } catch (Throwable e) { ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? return null; ? ? ? } ? } } 3.3 创建控制类 package com.qli.controller; import com.qli.config.RequestLog; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; ? @RestController public class TestController { ? ? @RequestMapping("/requestLog") ? public String requestLog(){ ? ? ? return "first controller"; ? } } 执行结果: 方法环绕start..... URL : http://localhost:8088/requestLog HTTP_METHOD : GET IP : 0:0:0:0:0:0:0:1 CLASS_METHOD : com.qli.controller.TestController.requestLog ARGS : [] 方法环绕proceed,结果是 :first controller 方法最后执行..... 方法的返回值 : first controller 上边是创建一个切面通过 @Pointcut("execution(public * com.qli.controller.TestController.*(..))")注解来限制切入点是controller包下TestController控制类下所有的方法都是切入点,那么congtroller包下其他控制类的方法就是连接点。 3.4创建自定义注解 3.4.1自定义注解之前需要了解的概念
3.5 实现 3.5.1 创建自定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface RequestLog { String desc() default "无信息"; } 3.5.2 创建自定义注解时候后将会触发的切面 package com.qli.config; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Component @Aspect @Order(1) public class RequestAspect { @Pointcut(value = "@annotation(com.qli.config.RequestLog)") public void access() { } @Before("access()") public void deBefore(JoinPoint joinPoint) throws Throwable { System.out.println("second before"); } @Around("@annotation(requestLog)") public Object around(ProceedingJoinPoint pjp, RequestLog requestLog) { //获取注解里的值 System.out.println("second around:" + requestLog.desc()); try { return pjp.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); return null; } } } 3.5.3 在控制层添加 @RequestLog(desc = "second") @RequestMapping("/second") public Object second(){ return "second controller"; } 执行结果 second around:second second before 如果将两个切面的切入点都包含有second这个方法的时候,浏览器访问http://localhost:8088/second的执行结果如下 second around:second second before 方法环绕start..... URL : http://localhost:8088/second HTTP_METHOD : GET IP : 0:0:0:0:0:0:0:1 CLASS_METHOD : com.qli.controller.TestController.second ARGS : [] 方法环绕proceed,结果是 :second controller 方法最后执行..... 方法的返回值 : second controller 执行顺序: spring aop就是一个同心圆,要执行的方法为圆心,最外层的order最小。从最外层按照AOP1、AOP2的顺序依次执行doAround方法,doBefore方法。然后执行method方法,最后按照AOP2、AOP1的顺序依次执行doAfter、doAfterReturn方法。也就是说对多个AOP来说,先before的,一定后after。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
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 4:56:15- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |