1.如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志
2.springbootaopï¼
3.SpringBoot基础之AOP&AspectJ
4.SpringBoot的AOP(@aspect注解)的简单使用
5.Springboot整合AOP和注解,实现丰富的切面功能
如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志
首先,我们来观察一下切面日志的输出效果。在了解实现方法之前,.net web 发布 源码我们可以看到每个请求的开始与结束都很清晰,同时打印了以下参数:
效果看起来还不错,接下来我们将一步步实现它。
二、添加 AOP Maven 依赖
在项目的 pom.xml 文件中,添加以下依赖:
三、自定义日志注解
接下来,我们来定义一个日志注解,如下所示:
源代码如下:
到这里,一个完整的自定义注解就定义完成了。
四、配置 AOP 切面
在配置 AOP 切面之前,我们需要了解一些 aspectj 相关注解的作用。
定义好切点后,我们可以围绕这个切点进行操作。接下来,竞猜源码搭建定义一个 WebLogAspect.java 切面类,并声明一个切点。
然后,定义 @Around 环绕,用于何时执行切点。
接下来,看看 @Before 方法。
最后,用 @After 来做收尾。在每个接口的最后,打印日志结束标志。到这里,切面相关的代码就完成了。
五、如何使用?
因为我们的切点是自定义注解 @WebLog,所以我们只需要在 Controller 控制器的每个接口方法添加 @WebLog 注解即可。如果我们不想某个接口打印出入参日志,可以不加注解。
六、文件上传是否有效?
对于文件上传,不论是文字挂机源码单文件上传还是多文件上传,切面日志都运行良好。有兴趣的小伙伴可以尝试一下。
七、如何在开发环境和测试环境中使用?
对于性能要求较高的应用,我们可以在开发环境或测试环境中使用,而不在生产环境中打印日志。我们只需为切面添加 @Profile 即可。
八、如何指定多切面的优先级?
如果我们服务中定义了多个切面,比如针对 Web 层接口,我们不仅想要打印日志,还要校验 token 等。我们可以通过 @Order(i) 注解来指定优先级。i 值越小,优先级越高。
springbootaopï¼
springbootaopèæ¶é¿
1ãä¸ä¸ªè±0.1ç§ï¼ä¸ªå°±1ç§ï¼ä¸ªå°±ç§äºâ¦ä»¥æ¤ç±»æ¨ï¼è¿ä¸ç¹å°±æ¯æ容ææ³æç½çå°æ¹äºãspringbootçèªå¨é ç½®ãèªå¨é ç½®æ¯springbootçä¸ä¸ªç¹è²ï¼ä½æ¯ä¹æ¯å®å¯å¨æ ¢çä¸ä¸ªå¼ç ã
2ãæè§å¾æ¯ä¸å¯è½ç¡®ä¿3ç§çï¼å ä¸è¯´ç¨åºæ¬èº«ï¼ä»æ¥æ¶è¯·æ±ï¼å°è¿å ¥åé¢ï¼å°åé¢å¤çï¼æåè¿åæ°æ®è¿ä¸è¿ç¨ï¼è¿è¡å®å°±éè¦èè´¹ä¸å®çæ¶é´ãèä¸æçä½ ç线ç¨æ± 深度åªæï¼é«å¹¶åä¸ï¼å¾å®¹æåºç°èµæºæ¢å¤ºã
3ãå®æ¶ä»»å¡é»è®¤æ¯å线ç¨çï¼å¦æ认为æç»æ¶é´è¾é¿ï¼å°±ä¼å°åé¢çå®æ¶ä»»å¡æ延ï¼å¯¼è´ä¸¢å¤±ä»»å¡ã
4ãç½ç»ä¸ç¨³å®å¯¼è´çãæå¡å¨springboot对ç½ç»çè¦æ±æ¯å¾é«çï¼å¨æ¥è¯¢æ¶éè¦ä¿æç½ç»çæµç ï¼å¦åæ¥è¯¢çé度ä¼ä¸ç¨³å®ãSpringBootæ¯ä¸ä¸ªæ¡æ¶ï¼ä¸ç§å ¨æ°çç¼ç¨è§èï¼ä»ç产çç®åäºæ¡æ¶ç使ç¨ã
5ãå¯ä»¥æ¿å°åå§çHTTP请æ±åååºçä¿¡æ¯ï¼ä¹å¯ä»¥æ¿å°ä½ çæ£å¤ç请æ±æ¹æ³çä¿¡æ¯ï¼ä¹å¯ä»¥ä¼ è¿åæ°çé£ä¸ªå¼ãå®ç°Filteræ¥å£å®ç°HandlerInterceptoræ¥å£ï¼ç¶åé ç½®è¿Springã
6ã)ä¸è¦è°è®º1)æ¥å¤©ãæ ¸å¿çiocãaopææ¯åioc解è¦ä½¿å¾ä»£ç éç¨æ§åå¯ç»´æ¤æ§å¤§å¤§æé«ãaopæä¾äºå沿çç¼ç¨ï¼è¿ä¹æé«äºç产çã2)springmvcï¼ç¸æ¯struts2çmvcæ¡æ¶ï¼ä¸æstruts2æé£ä¹å¤å®å ¨æ¼æ´ï¼å°±æ¯ç±»æ¦æªã
springbootå¨ææ·»å aopåé¢å¼å ¥aopçstarterï¼ç¬¬ä¸æ¥ï¼ç¬¬äºæ¥ï¼jarå æä¹åï¼åªéè¦å®ç°å¯¹åºçåé¢æ¹æ³å°±è¡äºé常ææ¹æ³åæ¦æªï¼æ¹æ³åæ¦æªï¼ä»¥åå¼å¸¸æ¦æªãéè¿å¨è¿äºæ¦æªä¸ç¼åèªå·±çä¸å¡å¤çï¼å¯ä»¥è¾¾å°ç¹å®çéæ±ã
å¨å建AOP代çä¹åéè¦æç¸å ³çåé¢é 置解ææä¸é¢ç±»å¾ä¸çæ¥å£åç±»ç对象ï¼å¯¹äºProxyFactoryBeanæ¥è¯´ï¼æ²¡æè¿ä¸ªè¿ç¨ï¼å 为è¿ç§æ¹å¼ä¸ä¸è½ä½¿ç¨åç¹ã
å¯ä»¥çä¸é¢å ³äºAOPçé»è®¤é ç½®å±æ§ï¼å ¶ä¸spring.aop.autoå±æ§é»è®¤æ¯å¼å¯çï¼ä¹å°±æ¯è¯´åªè¦å¼å ¥äºAOPä¾èµåï¼é»è®¤å·²ç»å¢å äº@EnableAspectJAutoProxyã
AOPåé¢åæ³ä¸æ³å没æå ³ç³»ï¼å ³é®è¿æ¯@Pointcutåå¾å¯¹ä¸å¯¹ã
springbootæä¹æ·»å ä¸ä¸ªaopäºä»¶
å¼å ¥aopçstarterï¼ç¬¬ä¸æ¥ï¼ç¬¬äºæ¥ï¼jarå æä¹åï¼åªéè¦å®ç°å¯¹åºçåé¢æ¹æ³å°±è¡äºé常ææ¹æ³åæ¦æªï¼æ¹æ³åæ¦æªï¼ä»¥åå¼å¸¸æ¦æªãéè¿å¨è¿äºæ¦æªä¸ç¼åèªå·±çä¸å¡å¤çï¼å¯ä»¥è¾¾å°ç¹å®çéæ±ã
å¨springBootä¸ï¼åªéè¦å å ¥POMå°±å¯ä»¥äºï¼é å注解使ç¨å³å¯ãæ¥ä¸æ¥å°±æ¯äºå¡çæ§å¶äºãé¦å äºå¡æå å¤§ä¼ æå±æ§ï¼å ¶ä¸æ常è§çï¼ç¨å¾æå¤å°±PROPAGATION_REQUIREDãPROPAGATION_REQUIRES_NEWãPROPAGATION_NESTEDè¿ä¸ç§ã
åè¨ï¼è¯¥å客主è¦æ¯è®°å½èªå·±å¦ä¹ çè¿ç¨ï¼æ¹ä¾¿ä»¥åæ¥çï¼å½ç¶ä¹å¸æè½å¤å¸®å°å¤§å®¶ãåè®°ï¼æ¬æ¬¡å享å°æ¤ç»æï¼æ¬äººæ°´å¹³æéï¼é¾å æé误æéæ¼ä¹å¤ï¼æ大家ææ£åè° è§£ï¼æ¬¢è¿è¯è®ºçè¨ã
SpringBootæ ¸å¿åç:èªå¨é ç½®ãäºä»¶é©±å¨ãCondition1ãSpringBootå¨å¯å¨çæ¶åä»ç±»è·¯å¾ä¸çMETA-INF/spring.factoriesä¸è·åEnableAutoConfigurationæå®çå¼å°è¿äºå¼ä½ä¸ºèªå¨é ç½®ç±»å¯¼å ¥å®¹å¨ï¼èªå¨é 置类就çæï¼å¸®æ们è¿è¡èªå¨é 置工ä½ã
2ãSpringæ¯æJavaé ç½®åXMLé ç½®ï¼ä»ä»¬ä¸ºåºç¨ç¨åºå¼å¯äºç¹å®çç¹æ§ååè½ï¼SpringBootå®ç°äºèªå¨é ç½®ï¼å¯ä»¥åå°é ç½®è´æ ã
3ãæ¹æ³/æ¥éª¤SpringBootå¯å¨çæ¶åå 载主é 置类ï¼å¼å¯äºèªå¨é ç½®åè½@EnableAutoConfigurationã请ç¹å»è¾å ¥å¾çæè¿°EnableAutoConfigurationçä½ç¨æ¯å©ç¨AutoConfigurationImportSelectorç»å®¹å¨ä¸å¯¼å ¥ä¸äºç»ä»¶ã
4ã第ä¸æ¥ï¼å¯å¨ä¸ä¸ªæ°çSpringBoot项ç®å©ç¨å¯å¨.spring.ioå建ä¸ä¸ªâç½ç»â项ç®ãå¨âä¾èµé¡¹â对è¯æ¡ä¸æ索并添å âwebâä¾èµé¡¹ï¼å¦å±å¹æªå¾æ示ãç¹å»âçæâæé®ï¼ä¸è½½zipï¼ç¶åå°å ¶è§£å缩å°è®¡ç®æºä¸çæ件夹ä¸ã
5ãå建ä¸ä¸ªSpringApplication对象æ¶ï¼ä¼è°ç¨å®èªå·±çinitializeæ¹æ³æ§è¡æ ¸å¿runæ¹æ³åå§åinitializeæ¹æ³æ§è¡å®ä¹åï¼ä¼è°ç¨runæ¹æ³ï¼å¼å§å¯å¨SpringBootã
springbootaop解å³æ¾ä¸å°jarä¸æ件å°åä½æ件æ¾å¨javaç¨åºresourcesèµæºæ件ä¸å è½½ï¼Thread.currentThread().getContextClassLoader().getResource().getPath()è¿ç§æ¹å¼å¯ä»¥æ£ç¡®è·ååä½æ件路å¾ã
æ°å»ºSpringBoot项ç®åï¼é¡¹ç®æ£å¸¸è¿è¡ï¼ä½æ¯pom.xmlæ件æ示âProjectorg.springframework.bootï¼spring-boot-starter-parentï¼5notfoundâãåºç°è¿ç§é®é¢ï¼æ¯ç±äºå¨å½åçä»åºä¸æ¾ä¸å°æå®ççæ¬Jarå ã
ä¸è¬æ两ç§æ¹æ³ã1ï¼å°æ¬å°jarå å®è£ å¨æ¬å°mavenåºï¼2ï¼å°æ¬å°jarå æ¾å ¥é¡¹ç®ç®å½ä¸ã
æ没æç¨è¿springclasspathï¼applicationContext.xmlè¿ä¸ªé ç½®ï¼å¦ä½ å¾ä¸æ示ï¼æ¾å¨äºresourcesä¸ï¼é£ä¹å¨å·¥ç¨ä¸æ¯å¯ä»¥è¿è¡çï¼åªæ¯æå å°jarä¸ä»¥åæ¾ä¸å°ï¼æå ç¹çæµresourcesä¸çé ç½®æ件ï¼æ²¡ææ¾å è¿å»ã
ç±äºSpringBootæå åï¼é»è®¤æ¯ä¸è½å è½½å¤é¨çjaræ件ï¼åªè½é»è®¤å è½½ymlæ件ã
SpringBoot基础之AOP&AspectJ
在SpringBoot中,AOP与AspectJ是关键的依赖,用于实现面向切面编程,使得代码逻辑清晰且易于维护。以日志切面为例,通过@Before("execution( (..))")注解,事业伙伴源码可以实现对某个方法的前置处理,这里的(..)代表同一包路径下的方法。具体应用中,execution( (..))可以精确到指定的返回类型、方法名与参数,例如@Before("execution( hello())")则表示匹配带有一个任意类型参数且返回类型无限制的hello方法。
通过配置Pointcut,可以替换原有逻辑,实现更灵活的切点控制。在Spring中,可以利用AspectJ的特性,通过EnableLoadTimeWeaving功能动态加载切面,增强系统的可扩展性。
Spring提供了多种内置的拦截器,如CustomizableTraceInterceptor、SimpleTraceInterceptor、DebugInterceptor、PerformanceMonitorInterceptor、AsyncExecutionInterceptor与ConcurrencyThrottleInterceptor等,分别用于日志记录、性能监控、娱乐机器源码异步调用与并发控制。例如,PerformanceMonitorInterceptor使用StopWatch进行精确到毫秒级的性能测量,适合于对性能敏感的应用场景。
在处理异常逻辑时,SpringBoot提供了CatchInterceptor,允许缓存方法调用结果,避免重复计算,简化了缓存逻辑的编写。
SpringBoot中还集成了CircuitBreaker机制,用于处理网络或服务间的不稳定问题。通过监控请求响应情况,当发现异常时,CircuitBreaker会进入断路状态,避免系统因不稳定服务而崩溃。例如,在调用远程服务时,如果连续失败达到一定次数,则触发断路,后续请求直接返回错误信息,直到服务恢复。
综上所述,SpringBoot的AOP与AspectJ框架提供了丰富的功能,从日志记录、性能监控到异常处理与服务间通信优化,都得以高效实现,大大增强了应用的健壮性与可维护性。通过灵活配置与利用内置的拦截器,开发者可以更专注于业务逻辑的实现,而将复杂度较高的系统维护工作交给框架处理。
SpringBoot的AOP(@aspect注解)的简单使用
在SpringBoot中,利用AOP(面向切面编程)进行代码组织,有助于提高代码复用性和降低耦合度。在具体实现时,需要关注如何导入依赖,创建并使用Aspect类,以及理解关键注解和类的运用。
首先,导入Spring AOP的依赖包至关重要。这一步确保了Spring容器能够识别并管理切面类。
其次,直接编写Aspect类是创建切面的一种方法。在类中定义切点(Pointcut),通常包括方法签名和表达式两个部分。方法签名用于定义匹配的类和方法,表达式则描述了在何时执行增强代码。重要的是,方法签名需要是公共且无返回值的,用来避免不必要的代码执行。
为了便于理解,可以使用注解来简化Pointcut的定义。常用的注解包括@Aspect(声明切面类)、@Component(整合到Spring管理中)、@Pointcut(定义切点)、以及针对增强操作的注解,如@Before、@AfterReturning、@After和@AfterThrowing。
在实际开发中,Spring AOP提供了强大的功能,如获取JoinPoint以访问被代理类、方法和参数,以及使用RequestAttributes来操作HttpServletRequest对象。这些功能常用于实现如权限校验、日志记录等需求,原理基于动态代理机制。
常用的注解包括@Aspect用于声明切面类,@Pointcut用于定义切点,以及针对不同增强操作的注解,如@Around、@Before、@After、@AfterReturning和@AfterThrowing。
在SpringBoot中,AOP的应用通常围绕具体需求展开,如实现权限校验、日志记录等。AOP通过定义切点和增强策略,使得开发人员可以在不修改原有代码的情况下,实现特定的行为增强。
举例说明,假设我们想要在所有控制器方法执行前后添加日志记录。可以通过创建一个Aspect类,定义切点和相应的增强逻辑,然后在控制器类上应用这个切面。通过这种方式,实现了代码的解耦和可重用性。
总结来说,SpringBoot中的AOP提供了强大的功能,通过合理的切面设计和注解使用,可以有效地提高代码的可维护性和扩展性。使用@aspect注解进行简单使用,主要关注切点定义、增强策略的实现以及依赖的正确导入,即可在项目中灵活应用AOP技术。
Springboot整合AOP和注解,实现丰富的切面功能
在之前的文章《Spring AOP与AspectJ的应用详解》中,我们已经探讨了AOP的基本使用。本文将深入讲解如何结合注解,进一步提升AOP的灵活性。我们以实现一个简单的计时功能为例,来展示这一过程。
首先,我们创建一个自定义注解,为后续的切面处理做准备:
<!-- 注解定义 -->
然后,在一个Service类中,我们应用这个注解到需要计时的方法:
<!-- Service中的方法 -->
这个方法会被控制器调用,进而触发我们的AOP处理:
<!-- 控制器调用 -->
关键在于实现切面,利用Spring的@Around注解来识别带有我们自定义注解的方法。表达式如下,务必确保其准确性,以避免识别错误和潜在的多次调用问题(更多细节可参考Stackoverflow):
<!-- 切面实现 -->
@Around("@annotation(com.pkslow.springboot.aop.PkslowLogTime) && execution(* *(..))")
这里借助Spring的StopWatch来记录方法执行时间。
接下来,我们进行测试。通过Maven构建项目:
<!-- 测试阶段 -->
在日志中,你会看到切面织入的痕迹:
<!-- 日志输出 -->
启动应用并访问相关接口,你会看到计时信息的实时记录:
总的来说,通过注解与AOP的结合,我们可以轻松实现各种功能,并且通过注解的参数化和组合,进一步增强了灵活性。如果你对这个例子感兴趣,可以在GitHub上查看详细代码:<a href="github.com/LarryDpk/pks...">github.com/LarryDpk/pks...