Spring AOP注解的学习与实践

简介: 使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

Spring AOP注解的学习与实践


AOP


AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。


AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。


使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。


AOP核心概念


1、横切关注点


对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点


2、切面(aspect)


类是对物体特征的抽象,切面就是对横切关注点的抽象


3、连接点(joinpoint)


被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器


4、切入点(pointcut)


对连接点进行拦截的定义


5、通知(advice)


所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类


6、目标对象


代理的目标对象


7、织入(weave)


将切面应用到目标对象并导致代理对象创建的过程


8、引入(introduction)


在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段


Spring对AOP的支持


Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:


1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了


2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB


AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:


1、定义普通业务组件


2、定义切入点,一个切入点可能横切多个业务组件


3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作


所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法


Spring-aspects


指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式


(1) AOP切面编程主要步骤:  

 

           a、将业务逻辑类和切面类都加入到容器中,告诉Spring哪个是切面类(@Aspect)

           b、在切面类的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)

           c、开启基于注解的AOP模式@(@EnableAspectJAutoProxy)


(2) 详细步骤:


           1、导入aop模块

           2、定义业务逻辑类(业务逻辑运行日志进行记录,方法之前,异常,结束都希望有输出信息)

           3、定义一个日志切面类(切面类里面的代码需要动态切入到运行方法中)

               /*

                * 通知方法:

                *     前置通知(@Before):在目标方法执行之前运行

                *     后置通知(@After):在目标方法执行之后运行(无论方法正常还是异常结束都执行)

                *     环绕通知(@Arround):动态代理,手动推进目标方法运行(jionPoint.procced())

                *     异常通知(@AfterThrowing):在目标方法运行出现异常的时候执行

                *  返回通知(@AfterReturning):正常返回之后通知

                * */

           4、给切面类的目标方法标注何时何地运行(通知注解)

           5、将切面类和目标类(目标方法所在类)都加入到容器中

           6、告知Spring哪个类是切面类(给切面类加注解)

           7、开启基于注解版的切面功能:

               //(1)传统方式:

               //(2)注解方式:给配置类@EnableAspectJAutoProxy

           8、在Spring中很多@EnableXxx:开启一项功能来替代以前的XMl方式


@Aspect举例


@Aspect//告诉Spring,当前类是一个切面类
public class LogAspect {
  /*
   * 抽取公共的切入点表达式
   *  1、本类引用@Pointcut()
   *  2、其他切面引用@Pointcut("com.phubing.aop.LogAspect.pointCut()")
   * */
  @Pointcut("execution(public int com.phubing.aop.MathCalculator.div(int,int))")
  public void pointCut(){};
  //在目标方法执行之前切入,(切入点表达式)--指定在哪个方法切入
  @Before("pointCut()")
  public void logStart(JoinPoint joinpoint) {
    //joinpoint.getSignature().getName():获取方法的签名
    //joinpoint.getArgs():目标方法运行需要使用的参数列表
    Object[] args = joinpoint.getArgs();
    System.out.println(""+joinpoint.getSignature().getName()+"运行了,参数列表是:"+args);
  }
  @AfterThrowing(value="pointCut()",throwing="exception")
  //JoinPoint joinpoint:必须写在参数的第一位,否则Spring无法识别
  public void logException(JoinPoint joinpoint,Exception exception) {
    System.out.println(joinpoint.getSignature().getName()+"异常信息: "+exception);
  }
  //"pointCut()":切入点引用的表达式
  //returning="":指定该参数由谁来封装返回值
  @AfterReturning(value="pointCut()",returning="result")
  //Object result:使用Object封装所有类型的返回值
  public void logReturn(Object result) {
    //方法正常返回,想要得到返回值
    System.out.println("除法正常返回了,计算结果:{"+result+"}");
  }
  @After("pointCut()")
  public void logEnd(JoinPoint joinpoint) {
    Object[] args = joinpoint.getArgs();
    System.out.println(joinpoint.getSignature().getName()+"结束了,参数列表是:"+args);
  }
}


@EnableAspectJAutoProxy:(AOP原理实现重要组件)


给容器中注册了什么组件,这个组件什么时候工作,这个组件工作时的功能是什么


AOP整个功能要起作用,均是由@EnableAspectJAutoProxy入手:


A、在该注解里调用了@Import(AspectJAutoProxyRegistrar.class)


给容器中导入了AspectJAutoProxyRegistrar组件,利用AspectJAutoProxyRegistrar给容器中注册Bean(ImportBeanDefinitionRegistrar:可以将自定义组件注册给  BeanDefinitionRegistry)


① 运行时,先注册registerAspectJAnnotationAutoProxyCreatorIfNecessary组件(如果需要的情况下),


② 然后调用registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null)方法,


③ 上一个方法调用registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source)来注册或者升级


④ registerOrEscalateApcAsRequired方法传入了一个类型为AnnotationAwareAspectJAutoProxyCreator的参数


⑤ 下一步判断,如果容器中已经包含该名字而且这个Creator的名是internalAutoProxyCreator的话,然后进行一系列工作


⑥ 由于是第一次创建,所以会创建一些Bean的定义信息,即AnnotationAwareAspectJAutoProxyCreator等,包括利用registry把将要在容器中创建的Bean的进行定义(即Bean的定义就是要创建AnnotationAwareAspectJAutoProxyCreator),然后这个Bean的名称就是internalAutoProxyCreator,该Bean的注册信息正好注册在BeanDefinitionRegistry中


⑦ 第一步做完之后就相当于给容器注册了一个名为EnableAspectJAutoProxy的Bean,然后把EnableAspectJAutoProxy注解的内容信息取出

⑧ 取出之后检查是否为true,如果是,则做一系列工作


if(enableAspectJAutoProxy.getBoolean("proxyTargetClass")){
    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}


⑨ 再看如果为true,如果是则暴露一些代理的一些Bean(后面再讲)


if(enableAspectJAutoProxy.getBoolean("exposeProxy")){
    AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}


B、第一步完成


即利用EnableAspectJAutoProxy中的AspectJAutoProxyRegistrar给容器注册一个AnnotationAwareAspectJAutoProxyCreator(注解装配模式的Aspect切面自动代理创建器),相当于帮我们注册一个自动代理创建器,那这个创建器是什么?(子类 -> 父类)


① AnnotationAwareAspectJAutoProxyCreator -> AspectJAwareAdvisorAutoProxyCreator -> AbstractAdvisorAutoProxyCreator

      -> AbstractAutoProxyCreator(抽象的自动代理创建器)

      -> SmartInstantiationAwareBeanPostProcessor(Bean的后置处理器),BeanFactoryAware(能调用setBeanFactory()--即能把Bean工厂作为参数传递进来)


② 关注SmartInstantiationAwareBeanPostProcessor(Bean的后置处理器):在Bean初始化前后所做的事情、自动装配BeanFactory    


C、AnnotationAwareAspectJAutoProxyCreator(步骤)


① AbstractAutoProxyCreator

    a、this.setBeanFactory()

    b、AbstractAutoProxyCreator有后置处理器的逻辑


② AbstractAdvisorAutoProxyCreator

    a、虽然其父类(AbstractAutoProxyCreator)有setBeanFactory(),但在子类中已被重写(调用initBeanFatory())


③ AspectJAwareAdvisorAutoProxyCreator


④ AnnotationAwareAspectJAutoProxyCreator

    a、initBeanFatory()---为什么会有?

          因为在其父类中使用setBeanFactory()调用该方法,虽然父类中有写,但是被此类重写了,所以父类在进行setBeanFactory()调用的是此类的initBeanFatory()


D、AnnotationAwareAspectJAutoProxyCreator(创建和注册该类的过程)


① 启动时,首先创建一个IOC容器(AnnotationApplicationCOntext()),调用其一个有参构造器,传入配置类


   A、其有参构造器分为三步:


          a、this();(无参构造器创建对象)


          b、register(annotatedClasses);(再来注册一个配置类)


          c、refresh();(接着调用此方法,刷新容器)

                1) refresh()中重要的是registerBeanPostProcessors(beanFactory);--注册Beanpost控制处理器(注册这些Bean的后置处理器,用于拦截创建操作)

                2)registerBeanPostProcessors(beanFactory)会调用PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);

                3)如何注册Bean的后置处理器?


第一步:

   先getBeanNamesForType(BeanPostProcessor.class, true, false);(拿到IOC容器中所有需要创建对象的Bean的类型){


       为什么IOC中会有一些已经定义的Bean?


           第一步中传入了配置类,然后在解析配置类的时候,有一个注解@EnableAspectJAutoProxy,之前提到过,


            它会在IOC容器中创建一个AnnotationAwareAspectJAutoProxyCreator,以及容器中还有一些默认的后置处理器的Bean等,只是还没有创建对象,都只是一些定义(有处理AutoWired、Required、Common以及internal等注解的处理器),前面在分析@EnableAspectJAutoProxy的时候,它会给容器中注册一个internalAutoProxyCreator组件(只是当时注册是BeanDefination--Bean的注册信息)


            还有一些其他逻辑{


                它会给beanFatory还额外加了一些BeanPostProcessor,从这些BeanProcessor从分离,区分哪些是实现了PriorityOrdered

         

List priorityOrderedPostProcessors = new ArrayList();


                做了一些相应处理:


                    是否实现了某个接口,如实现了PriorityOrdered(Order子类,有优先级排序功能),则保存在priorityOrderedPostProcessors.add(pp);


                    分为三步:

                        First:先注册BeanPostProcessor,实现了PriorityOrdered接口(相当于优先注册该接口)

                        Next:再实现Orderd接口,因此在容器中注册

                        Third:普通的BeanPostProcess的注册(没实现优先级接口)

             }


             而所谓的注册{


                 1) 拿到BeanPostProcessor名字,然后从beanFatory中获取

                     A、调用doGetBean方法,然后doGetBean方法调用getSingleton()方法,但是第一次获取的时候容器中又不会目标Bean的名字, 如果有问题导致获取不到,就会调用和getObject()方法,而在getObject()中会创建一个Bean,然后保存在容器中{

                         a、如何创建internalAutoProxyCreator的BeanPostProcessor(类型为AnnotationAwareAspectJAutoProxyCreator){


                            1) 创建Bean实例


                            2) populateBean(beanName,mbd,instanceWrapper)--给Bean的属性赋值


                            3) initializebean:初始化Bean(后置处理器就是在此Bean的前后进行工作的){


                               i、invokeAwareMethods()--判断目标Bean是否为Aware接口的实现类,如果是则判断具体是哪一个Aware,然后调用相关的Aware方法(处理Aware接口的回调)


                               ii、applyBeanpostprocessorsbeforeinitlalization()--应用后置处理器的beforeinitlalization,先拿到所有的后置处理器,调用后置处理器的postProcessorInitialization()


                               iii、invokeIntitMethods()--执行自定义的初始化方法(使用@Bean指定初始化、销毁等方法是什么)


                               iiii、applyBeanPostProcessorsAfterInitializationl()执行后置处理器的


postProcessorAfterInitialization()
                            }
                         }
                     }
             }
}

       

第二步{


  ① 实现了BeanFacoryAware接口,如果是则调用AbstractAutoCreator的setBeanFactory(),


  ② 然后再调用InitBeanFactory()方法


     A、相当于创建了两个东西

         a、一个是ReflectAspectJAdvisorFatory()

         b、另一个是Beanfactoryaspectjadvisorsbuilderadapter--将BeanFatory等重新包装

}

                     

第三步BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--aspectJAdvisorBuilder


第四步把BeanPostProcessor注册到BeanFactory里中:beanFactory.addBeanPostProcessor(postProcessor)


E、AnnotationAwareAspectJAutoProxyCreator(作为后置处理器是如何运作的)


① 先到setBeanFactory()方法,一直到AbstractAutoProxyCreator,然后调用postProcessBeforeInstantiation()方法{

      1) 与postProcessBeforeInitzation()有何区别?

            A、AbstractAutoProxyCreator实现的是SmartInstantiationAwareBeanPostProcessor,而实现的类继承是InstantiationAwareBeanPostProcessor,而继承的类继承的是BeanPostProcessor,也就是说AnnotationAwareAspectJAutoProxyCreator是InstantiationAwareBeanPostProcessor类型的后置处理器

  }


② finishbeanfactoryinitialization(beanfactory);完成BeanFactory初始化工作(创建剩下的Bean实例)--IOC容器中的一些组件例如RegisterBeanPostProceesor早就已经被创建

   A、遍历获取容器中所有的Bean,依次创建对象--getBean(beanName)  getBean()<--doGetBean()<--getSingleton()      


③ 创建Bean


    【AnnotationAwareAspectJAutoProxyCreator在所有Bean创建之前会有一个拦截,因为它是InstantiationAwareBeanPostProcessor类型的后置处理器,所以会调用postProcessorsBeforeInstantiation()】


              A、先从缓存中获取当前Bean,如果能获取到,说明该Bean之前就被创建了,则直接使用,否则再创建(只要创建了Bean都会被缓存起来)


             B、CreateBean()--创建Bean


                   【BeanPostProcessor是在Bean对象创建完成初始化前后调用】

                   【AnnotationAwareAspectJAutoProxyCreator是在任何Bean创建实例之前尝试返回Bean的实例】

                   【InstantiationAwareBeanPostProcessor是在创建Bean实例之前先尝试用后置处理器返回对象】


                     a、拿到要创建Bean的定义信息,然后调用resolveBeforInstantiation(beanName,mbdToUse);--解析BeforInstantiation


                      1) 给后置处理器一个机会来返回代理对象,来替代目标的实例---也就是希望后置处理器能在此返回一个代理对象,如果能则返回,不能则调用doCreateBean()

                         i、后置处理器先尝试返回对象:

                            0、bean = applyBeanPostProcessorsBeforeInstantiation()--拿到所有的后置处理器,如果后置处理器如果是InstantiationAwareBeanPostProcessor,则调用postProcessorsBeforeInstantiation(),如果bean不等于null,则调用applyBeanPostProcessorsAfterInitializationl()


                      2) doCreateBean(beanName,mbdToUse,args)就是上面提到的真正创建Bean实例的流程  

         

F、postProcessBeforeInstantiation


(1) AnnotationAwareAspectJAutoProxyCreator[InstantiationAwareBeanPostProcessor]的作用就是每一个Bean创建之前调用postProcessBeforeInstantiation()方法


    1) 判断当前bean是否在advicedBeans中(保存了所有需要增强的Bean--需要切面来切的)


     2) 判断当前bean是否为基础类型(是否实现了Advice || PointCut || Advisor || AopInfrastructureBean接口)或者是否为切面(@Aspect或实现注解接口)


     3) 判断是否需要跳过()


           A、获取候选的增强器(切面中的通知方法--将这些通知方法的详细信息包装成了【List candidateAdvisors】)


                 a、每一个封装的通知方法的增强器时InstantiationModelAwarePointcutAdvisor


                  b、判断每一个增强器是否为AspectJPointcutAdvisor类型


            B、永远返回false


               (2) 创建对象


                    //包装如果需要的情况


                    1) postProcessAfterInstantiation 会 return wrapIfNecessary(bean,beanName,cachekey);

                          A、获取当前Bean的所有增强器(通知方法)

                                a、找到候选的能能在当前Bean能用增强器(找哪些通知方法需要切入到当前方法的)

                                b、获取到能再Bean中使用的增强器

                                c、给增强器排序

                          B、保存当前Bean在advisedBean中


               (3) 如果当前Bean需要增强,创建当前Bean的代理对象

                          A、获取所有的增强器(所有通知方法)

                          B、保存到proxyFactory

                          C、创建代理对象

                                 a、JdkDynamicAopProxy(config):JDK动态代理(实现了接口)

                                 b、ObjenesisCglibAopProxy(config):Cglib的动态代理


               (4) 给容器中返回当前组件使用cglib增强了的代理对象


               (5) 以后容器获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程

         

G、目标方法执行


(1) 容器中所创建的代理对象(cglib增强后的对象),这个对象保存了详细信息(薄如增强器,目标对象,XXX)

      1) CglibProxy.intercept();拦截工作逻辑


(2) 根据ProxyFactory对象获取目标方法将要执行方法的拦截器链

    List chain = this.advised.getInterceptorsAndDynamicInrterceptorAdvice(method,targetClass);

           1) List interceptorList保存所有拦截器(5个)

                 A、一个ExposeInvocationInterceptor 和 四个增强器


            2) 遍历所有的增强器,将他们转成interceptor[] interceptor = registory.getInterceptors(advisor)


            3) 将增强器转为List>MethodInterceptor>,如果是该种类型就直接转,如果不是仍需要一些增强器Adaptor再转换为Interceptor,转换完成返回Interceptor数组                


(3) 如果没有拦截器链,直接执行目标方法

       1) 拦截器链即每一个通知方法又被包装成方法拦截器,利用MethodInterceptor机制    


(4) 如果有拦截器链,把要执行的目标对象、方法、拦截器链。。传入CglibMethodInvocation对象并调用Object return mi.proceed()方法

         

H、拦截器链的触发过程

(1) 如果没有拦截器执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法


(2) 链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器返回之后再执行(拦截器链机制保证通知方法与目标方法的执行顺序)


总结:


1、@EnableAspectJAutoProxy 开启AOP功能


2、@EnableAspectJAutoProxy 会给容器中注册一个组件AnnotationAwareAspectJProxyCreator


3、AnnotationAwareAspectJProxyCreator是一个后置处理器


4、容器的创建流程:


       (1) registerBeanPostProcessors()注册后置处理器(AnnotationAwareAspectJProxyCreator对象)

       (2) 初始化剩下的单实例Bean

            1) 创建业务逻辑组件和切面组件

            2) AnnotationAwareAspectJProxyCreator对象拦截组件的创建过程

            3) 组件创建完成之后,判断组件是否需要增强

                 ① 需要则将切面的通知方法包装成增强器(Advisor)给业务逻辑组件创建一个代理对象(cglib)

 

5、执行目标方法


       (1) 代理对象执行目标方法


       (2) CglibProxy.intercept();

              1) 得到目标方法的拦截器链(增强器包装秤拦截器--MethodInterceptor)

              2) 利用拦截器链的链式机制,依次进入每一个拦截器进行执行

              3) 效果

                  A、正常执行:前置通知 --> 目标方法 --> 后置通知 --> 正常返回通知

                  B、出现异常:前置通知 --> 目标方法 --> 后置通知 --> 正常异常通知

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
基于springboot的儿童家长教育能力提升学习系统
本系统聚焦儿童家长教育能力提升,针对家庭教育中理念混乱、时间不足、个性化服务缺失等问题,构建科学、系统、个性化的在线学习平台。融合Spring Boot、Vue等先进技术,整合优质教育资源,提供高效便捷的学习路径,助力家长掌握科学育儿方法,促进儿童全面健康发展,推动家庭和谐与社会进步。
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段四:学术分析 AI 项目 RAG 落地指南:基于 Spring AI 的本地与阿里云知识库实践
本文介绍RAG(检索增强生成)技术,结合Spring AI与本地及云知识库实现学术分析AI应用,利用阿里云Qwen-Plus模型提升回答准确性与可信度。
2800 90
AI 超级智能体全栈项目阶段四:学术分析 AI 项目 RAG 落地指南:基于 Spring AI 的本地与阿里云知识库实践
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
1007 0
|
缓存 监控 Java
SpringBoot @Scheduled 注解详解
使用`@Scheduled`注解实现方法周期性执行,支持固定间隔、延迟或Cron表达式触发,基于Spring Task,适用于日志清理、数据同步等定时任务场景。需启用`@EnableScheduling`,注意线程阻塞与分布式重复问题,推荐结合`@Async`异步处理,提升任务调度效率。
1859 128
|
人工智能 监控 Java
Spring AI Alibaba实践|后台定时Agent
基于Spring AI Alibaba框架,可构建自主运行的AI Agent,突破传统Chat模式限制,支持定时任务、事件响应与人工协同,实现数据采集、分析到决策的自动化闭环,提升企业智能化效率。
Spring AI Alibaba实践|后台定时Agent
|
XML Java 数据格式
《深入理解Spring》:AOP面向切面编程深度解析
Spring AOP通过代理模式实现面向切面编程,将日志、事务等横切关注点与业务逻辑分离。支持注解、XML和编程式配置,提供五种通知类型及丰富切点表达式,助力构建高内聚、低耦合的可维护系统。
|
Java 测试技术 数据库
使用Spring的@Retryable注解进行自动重试
在现代软件开发中,容错性和弹性至关重要。Spring框架提供的`@Retryable`注解为处理瞬时故障提供了一种声明式、可配置的重试机制,使开发者能够以简洁的方式增强应用的自我恢复能力。本文深入解析了`@Retryable`的使用方法及其参数配置,并结合`@Recover`实现失败回退策略,帮助构建更健壮、可靠的应用程序。
1317 1
使用Spring的@Retryable注解进行自动重试
|
XML Java 数据格式
常用SpringBoot注解汇总与用法说明
这些注解的使用和组合是Spring Boot快速开发和微服务实现的基础,通过它们,可以有效地指导Spring容器进行类发现、自动装配、配置、代理和管理等核心功能。开发者应当根据项目实际需求,运用这些注解来优化代码结构和服务逻辑。
827 12
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
1001 2
|
传感器 Java 数据库
探索Spring Boot的@Conditional注解的上下文配置
Spring Boot 的 `@Conditional` 注解可根据不同条件动态控制 Bean 的加载,提升应用的灵活性与可配置性。本文深入解析其用法与优势,并结合实例展示如何通过自定义条件类实现环境适配的智能配置。
831 0
探索Spring Boot的@Conditional注解的上下文配置