Spring AOP 源码系列(一)解析 AOP 配置信息

Spring之aop源码解析 aop就是面向切面编程,是为了解耦而生。aop是不仅工作常用而且面试也经常问,所以看aop源码是非常有必要的。在看源码之前,我们先要带着结论去看源码,而不是一上来看的一脸懵逼,一定要先总后分。aop的流程就是在spring的生命周期过程中,会缓存所有的切面,然后在bean初始化的时候,它会找当前bean的所有方法是否跟缓存中的切面有匹配的,如果匹配,说明需要代理并创建代理对象,当调用被增强方法时,执行代理逻辑。本文基于springboot2.3.5.RELEASE,如果有错,欢迎指出。 阅读详情

在进行源码阅读之前建议先看一下这篇文章:Spring AOP 源码分析系列文章导读 by 田小波,写的非常好,推荐阅读。

关于 AOP 中常用的一些术语这里就不解释了,如果不清楚的建议先看一遍上面推荐的文章。

一、AOP 配置入口

在分析源码之前,我们先来看一下 XML 中关于 AOP 的配置:

    <bean id="userServiceImpl" class="com.jas.mess.aop.UserServiceImpl"/>
    <bean id="ownerAspect" class="com.jas.mess.aop.spring.OwnerAspect"/>

    <aop:config>
        <aop:aspect ref="ownerAspect">
            <aop:pointcut id="ownerPointcut" expression="execution(* com.jas.mess.aop.*.*(..))"/>
            <aop:before method="recordLog" pointcut-ref="ownerPointcut"/>
        </aop:aspect>
    </aop:config>

在以前的文章里有总结过,XML 文件的配置信息会被转化成 BeanDefinition,其中 AOP 相关的配置也不例外,从上面的例子中我们能看出一个明显的区别:普通的 bean 标签与 AOP 配置标签不一样,一个是 <bean /> 一个是 <aop />,除此之外你要想配置 AOP,还需要在 XMl 中引入 xmlns:aop="http://www.springframework.org/schema/aop" 命名空间。

普通的 bean 标签与 AOP 标签处理逻辑通过命名空间区分,下面我们来看源码。

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        // 命名空间检查,默认的命名空间是 "http://www.springframework.org/schema/beans"
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    // <bean /> 标签处理入口
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        // <aop /> 标签处理入口
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

上面我们说过,AOP 的命名空间是 http://www.springframework.org/schema/aop,因此会执行到 delegate.parseCustomElement(ele)。

    public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
        String namespaceUri = getNamespaceURI(ele);
        if (namespaceUri == null) {
            return null;
        }
        // 根据命名空间获取 handler
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        }
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }


    public BeanDefinition parse(Element element, ParserContext parserContext) {
        BeanDefinitionParser parser = findParserForElement(element, parserContext);
        return (parser != null ? parser.parse(element, parserContext) : null);
    }

上面的流程比较简单,根据命名空间 URI 获取命名空间 handler,这里对应的是 AopNamespaceHandler,通过 handler 去解析配置。handler 内部会根据标签配置信息得到 ConfigBeanDefinitionParser,最终调用 parse 方法。

    public BeanDefinition parse(Element element, ParserContext parserContext) {
        CompositeComponentDefinition compositeDef =
                new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
        parserContext.pushContainingComponent(compositeDef);

        // 注册 AspectJAwareAdvisorAutoProxyCreator 类型的beanDefinition,继承自 BeanPostProcessor
        configureAutoProxyCreator(parserContext, element);

        // 获取所有子标签
        List<Element> childElts = DomUtils.getChildElements(element);
        for (Element elt: childElts) {
            String localName = parserContext.getDelegate().getLocalName(elt);
            // 解析 <aop:poincut />
            if (POINTCUT.equals(localName)) {
                parsePointcut(elt, parserContext);
            }
            // 解析 <aop:>advisor />
            else if (ADVISOR.equals(localName)) {
                parseAdvisor(elt, parserContext);
            }
            // 解析 <aop:aspect />
            else if (ASPECT.equals(localName)) {
                parseAspect(elt, parserContext);
            }
        }

        parserContext.popAndRegisterContainingComponent();
        return null;
    }

这里涉及到一个 <aop:advisor /> 标签,大家可能不太清楚它的作用,advisor 与 advice(<aop:before />,<aop:after />…)功能类似,都可以用来增强目标方法,具体用法可以参考这篇文章:Spring Aop(八)——advisor标签 by 234390216

parse 方法会处理 <aop:config /> 标签下的子标签,具体的处理逻辑后面会分析到。在解析标签之前先调用了 configureAutoProxyCreator 方法,这个方法比较重要。

二、注册 AspectJAwareAdvisorAutoProxyCreator beanDefinition

    private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
        AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
    }

    public static void registerAspectJAutoProxyCreatorIfNecessary(
            ParserContext parserContext, Element sourceElement) {
        BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
                parserContext.getRegistry(), parserContext.extractSource(sourceElement));

        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);

        registerComponentIfNecessary(beanDefinition, parserContext);
    }

registerAspectJAutoProxyCreatorIfNecessary方法中有三个处理逻辑,下面一一来看下。

    @Nullable
    public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
            BeanDefinitionRegistry registry, @Nullable Object source) {
        // 注意这里传的是 AspectJAwareAdvisorAutoProxyCreator 类型
        return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
    }

    private static BeanDefinition registerOrEscalateApcAsRequired(
            Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

        // AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator"
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                int requiredPriority = findPriorityForClass(cls);
                if (currentPriority < requiredPriority) {
                    apcDefinition.setBeanClassName(cls.getName());
                }
            }
            return null;
        }

        RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
        beanDefinition.setSource(source);
        beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        // 注册一个类型为 AspectJAwareAdvisorAutoProxyCreator 的 beanDefinition
        registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
        return beanDefinition;
    }

注册一个类型为 AspectJAwareAdvisorAutoProxyCreator 的 beanDefinition,注意此时还没有创建 bean,AspectJAwareAdvisorAutoProxyCreator 其实是一个 BeanPostProcessor,后面在对方法增强的时候会用到,具体细节会在后面的文章里总结。

    private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
        if (sourceElement != null) {
            boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
            if (proxyTargetClass) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
            if (exposeProxy) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

检查 <aop:config />是否配置了 proxy-target-class 与 expose-proxy,如果有配置,则为 beanDefinition 添加 exposeProxy 与 proxyTargetClass 属性,这两个配置标签后面还会遇到,这里先简单介绍下作用。

proxy-target-class:默认为 false,如果设置为 true,会使用 CGLIB 创建代理对象
expose-proxy:默认为 false,作用:假设 A,B 方法都被增强,A 方法调用 B 方法,A 方法会被切面拦截,A 里的 B 方法是否会被切面拦截增强,默认不会

private static void registerComponentIfNecessary(@Nullable BeanDefinition beanDefinition, ParserContext parserContext) {
        if (beanDefinition != null) {
            parserContext.registerComponent(
                    new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));
        }
    }

注册组件。

三、解析 <aop:aspect ref="" id="" />

<aop:aspect /> 标签下可以配置多种类型的子标签,比如 <aop:before />、<aop:after />、<aop:pointcut />、<aop:declare-parents /> 等,不同类型的标签处理逻辑也是不一样的。

    private void parseAspect(Element aspectElement, ParserContext parserContext) {
        String aspectId = aspectElement.getAttribute(ID);
        // 切面 beanName
        String aspectName = aspectElement.getAttribute(REF);

        try {
            // 添加进 LinkedList
            this.parseState.push(new AspectEntry(aspectId, aspectName));
            List<BeanDefinition> beanDefinitions = new ArrayList<>();
            List<BeanReference> beanReferences = new ArrayList<>();

            // 获取  <aop:declare-parents /> 子标签
            List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
            for (Element declareParentsElement : declareParents) {
                beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
            }

            NodeList nodeList = aspectElement.getChildNodes();
            boolean adviceFoundAlready = false;
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                // 处理通知节点 <aop:before,after, around ... />
                if (isAdviceNode(node, parserContext)) {
                    if (!adviceFoundAlready) {
                        adviceFoundAlready = true;
                        if (!StringUtils.hasText(aspectName)) {
                            parserContext.getReaderContext().error(
                                    "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
                                    aspectElement, this.parseState.snapshot());
                            return;
                        }
                        beanReferences.add(new RuntimeBeanReference(aspectName));
                    }
                    // 处理通知
                    AbstractBeanDefinition advisorDefinition = parseAdvice(
                            aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
                    beanDefinitions.add(advisorDefinition);
                }
            }

            // 创建 AspectComponentDefinition
            AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
                    aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
            parserContext.pushContainingComponent(aspectComponentDefinition);

            // 获取所有切点 element
            List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
            for (Element pointcutElement : pointcuts) {
                parsePointcut(pointcutElement, parserContext);
            }

            parserContext.popAndRegisterContainingComponent();
        }
        finally {
            this.parseState.pop();
        }
    }

主要流程如下:

  1. 获取 <aop:aspect > 的 id 与 ref 属性,封装成 AspectEntry 添加到 parseState 集合中,流程处理完后,出栈
  2. 获取 <aop:declare-parents /> 子标签,如果有配置则封装成 beanDefinition
  3. 解析 <aop:aspect > 下所有子标签,循环处理通知配置
  4. 解析切点配置
   private AbstractBeanDefinition parseAdvice(
           String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
           List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

       try {
           this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));

           RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
           // 切面 bean(类)
           methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
           // 设置切面方法
           methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
           methodDefinition.setSynthetic(true);

           // 创建切面 BeanDefinition
           RootBeanDefinition aspectFactoryDef =
                   new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
           aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
           aspectFactoryDef.setSynthetic(true);

           // 创建通知 BeanDefinition,此时已明确通知类型
           AbstractBeanDefinition adviceDef = createAdviceDefinition(
                   adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
                   beanDefinitions, beanReferences);

           RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
           advisorDefinition.setSource(parserContext.extractSource(adviceElement));
           // 将上面创建的 adviceDef 注入到 advisorDefinition 中
           advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
           // <aop:aspect ref="" order="" />,控制切面方法优先级
           if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
               advisorDefinition.getPropertyValues().add(
                       ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
           }

           // 注册通知 BeanDefinition
           parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);

           return advisorDefinition;
       }
       finally {
           this.parseState.pop();
       }
   }

上面逻辑主要是创建出 advisorDefinition,并注册到 beanFactory 中,由此可见,我们配置的每一个通知,最终都会被转化成 beanDefinition 并注册到 IoC 容器中。

上面这个方法深追下去知识点还挺多的,比如 createAdviceDefinition 方法,注册 beanDefinition 时 beanName 的生成规则等,有兴趣的自己可以研究下,这里就不介绍了,看不懂的地方可以通过 DEBUG 的方式帮助理解。

    private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
        String id = pointcutElement.getAttribute(ID);
        // 获取切点表达式
        String expression = pointcutElement.getAttribute(EXPRESSION);

        AbstractBeanDefinition pointcutDefinition = null;

        try {
            this.parseState.push(new PointcutEntry(id));
            // 创建切点 beanDefinition,类型为 ConfigurableBeanFactory.SCOPE_PROTOTYPE
            pointcutDefinition = createPointcutDefinition(expression);
            pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));

            String pointcutBeanName = id;
            // 注册切点 BeanDefinition 到 beanFactory 中
            if (StringUtils.hasText(pointcutBeanName)) {
                parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
            }
            else {
                // <aop:pointcut id="" expression=""/> 没有配置 id 先生成 beanName 在注册到 beanFactory 中
                pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
            }

            parserContext.registerComponent(
                    new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
        }
        finally {
            this.parseState.pop();
        }

        return pointcutDefinition;
    }

    protected AbstractBeanDefinition createPointcutDefinition(String expression) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
        // 切点作用域原型
        beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        beanDefinition.setSynthetic(true);
        beanDefinition.getPropertyValues().add(EXPRESSION, expression);
        return beanDefinition;
    }

处理切点的逻辑与通知类似,注意切点 beanDefinition 的作用域并非单例而是原型,初始化 beanDefinition 后注册到 IoC 容器中。

参考

【Spring源码分析】AOP源码解析(上篇) by 五月的仓颉

Spring源码——AOP 前言 内容主要参考自《Spring源码深度解析》一书,算是读书笔记或是原书的补充。进入正文后可能会引来各种不适,毕竟阅读源码是件极其痛苦的事情。 本文主要涉及书中第七章的部分,依照书中内容以及个人理解对Spring源码进行了注释,详见Github仓库:https://github.com/MrSorrow/spring-framework 正式进入正文前,强烈推荐先阅读文末参考阅读第一篇:关于 S... 阅读详情

相关推荐

Spring AOP的三种配置方式与内部解析实现

AOP配置 在应用代码中,可以通过在spring的XML配置文件applicationContext.xml或者基于注解方式来配置AOP。 AOP配置的核心元素为:pointcut,advisor,aspect,pointcut用于定义需要该辅助功能的类或方法集合;advisor则是将advice和pointcut结合起来,在spring的IOC容器启动时,为pointcut匹配的类生成代理对象,使用拦截器拦截对应的方法的执行,将辅助功能advice添加进去;aspect表示一个完整切面,即在aspect对

m0_45270667的博客 4919

spring-AOP的实现

AOP(面向切面编程)的理解与实现1.什么是面向切面编程要理解面向切面编程,必须要理解切面的含义,切面是指在程序的许多地方都会应用到的功能,例如对于日志系统来说,记录日志就可以被当做一个切面,在一个应用程序的许多地方,日志都是不可或缺的,但在这些地方,我们主要的关注点却不一定记录日志上,比如当我们在开启一个数据库连接时,我们主要关注的点在于开启连接,而不是记录日志,举个现实中的例子就是,我们日常生活

qq_35488769的博客 388

Python + NX二次开发,如何配置Python的第三方库(包)?

地球人都知道python有强大的第三方库,可以各类骚操作,包括但不限于人工智能模块。在使用Python进行NX二次开发时,如果能够用得上这些第三方包,那将大大提高效率。本文详述了如何配置,实践证明:可行!

温良 1267

Java练习(十):Spring应用之AOP的@Before, @After操作(简单工程示例)

目录 1. 背景概念 1.1 定义 1.2 AOP的本质 1.3 AOP的实现 1.4各个名称的概念详解 2. 示例工程 2.1 maven的配置文件: pom.xml 2.2 bean配置文件: bean_aop.xml 2.3 接口和类的代码 2.3.1 接口:UserService 2.3.2实现接口的类:UserServiceImpl 2.3.3Before类:BeforeLog 2.3.4After类:AfterLog 2.4 测试类 1. 背景概念 1....

sulia1234567890的博客 9090

DIY便携式PEMF磁脉冲治疗仪:百元成本自制生物物理疗法设备

脉冲电磁场(PEMF)疗法是一种基于生物物理原理的非侵入性技术,它通过特定频率的电磁脉冲作用于细胞层面,影响细胞膜电位和离子通道活动,从而可能调节细胞代谢与功能。其技术价值在于提供了一种物理干预手段,在健康科技和生物黑客领域被探索用于放松、恢复等场景。实现PEMF的核心是通过信号发生与功率放大驱动电磁线圈产生可控磁场。本文以蓝牙音频模块和智能手机App为切入点,详细解析了如何利用低成本电子元件(如DFRobot XY-WRBT模块和漆包线线圈)构建一个可自定义频率的便携式PEMF设备,涵盖了从电路设计、线圈

weixin_31476015的博客 352

避坑指南:C#用S7NetPlus读写西门子PLC字符串(String/WString)的完整方案

本文详细解析了C#通过S7NetPlus读写西门子PLC字符串(String/WString)的完整方案,包括内存布局、编码差异和字节序处理等关键技术细节。提供了实战优化的代码示例和常见问题排查指南,帮助开发者避免乱码、截断等常见陷阱,提升工业自动化项目的开发效率。

weixin_32956805的博客 321

一篇文章彻底搞懂java AOP、@Before、@After、@AfterReturning、@AfterThrowing、@Around的使用、Spring AOP详解

Advice,确切地说它应该被理解为增强,前面也一直在强调方法的增强,那么接下来我们来看看在Spring AOP中是如何去实现方法的增强的。

qq_40585384的博客 1万+

3DGS实战笔记:从相机坐标系到屏幕像素,手把手推导高斯椭球的投影变换矩阵

本文详细解析了3D高斯散射(3DGS)技术中从相机坐标系到屏幕像素的几何变换过程,重点推导了高斯椭球的投影变换矩阵。通过视图变换、投影变换和视口变换的完整流程,结合雅可比矩阵处理协方差矩阵,实现了高效的三维重建与渲染。文章提供了Python代码示例,帮助开发者深入理解3DGS的核心几何变换机制。

weixin_28691741的博客 438

Spring @Aspect、@Before、@After 注解实现 AOP 切面功能

Spring AOP 注解概述 1、Spring 的 AOP 功能除了在配置文件中配置一大堆的配置,比如切入点、表达式、通知等等以外,使用注解的方式更为方便快捷,特别是 Spring boot 出现以后,基本不再使用原先的 beans.xml 等配置文件了,而都推荐注解编程。 @Aspect 切面声明,标注在类、接口(包括注解类型)或枚举上。 @Pointcut 切入点声明,即切入到哪些目标类的目标方法。 value 属性指定切入点表达式,默认为 "",用于被通知注解引用

蚩尤后裔-汪茂雄 7万+

Apple 网页 SRP 登录系列文章(四):Hashcash 工作量证明与完整登录流程

本文是Apple SRP登录系列文章的收官之作,重点解析了Apple独有的Hashcash工作量证明机制并展示了完整的登录流程实现。文章详细介绍了Hashcash的安全目的、格式标准、计算核心算法及难度评估方法,特别提供了Python实现代码。同时还讲解了如何动态获取服务器Hashcash参数以及建立容错机制。最后呈现了完整的Apple SRP登录主函数架构,为开发者提供了从理论到实践的全面指导。全文通过代码示例和流程分析,系统性地阐述了Apple安全登录机制的技术细节。

Sayid_Des的专栏 630

Java调用YOLOv26全解析:从ONNX模型部署到工业质检实战

本文分享了工业自动化领域使用Java调用YOLOv26进行零件缺陷检测的完整方案。通过YOLOv26s模型结合ONNX Runtime Java部署,误检率和漏检率显著降低(分别从12%降至2.1%,8%降至0.8%)。文章详细介绍了方案选型理由、环境配置避坑指南、ONNX模型导出步骤,以及Maven依赖配置(分CPU/GPU版本)。该方案直接在上位机Java环境中运行,避免了跨语言调用损耗,适合工业质检场景部署,提供了可复用的性能优化和多线程推理实现。

2601_94871597的博客 1108

详述Spring AOP中的@Before,@After,@AfterReturning,@AfterThrowing和@Around

AOP的定义:AOP将封装好的对象剖开,找出其中对多个对象产生影响的公共行为,并将其封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),切面将那些与业务无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。 简单来说,就是将多个对象中的,非核心重复性高的代码单独封装,以供调用。 极大地提高了代码复用率,降低了...

nairuozi的博客 6003

Oracle EBS(R12+)通过Multi-Org 多组织架构、Multi-Ledger 多账簿、SLA 子分类账会计、多币种引擎、多会计政策并行五大核心能力,为跨国企业提供一体化、自动化、合规的

Oracle EBS(R12+)提供全球会计核算解决方案,通过Multi-Org多组织架构实现跨国集团数据隔离与共享,支持四层组织结构(业务组→法律实体→经营单位→库存组织)。Multi-Ledger多账簿功能允许一笔业务多准则自动核算,包含主账簿、辅助账簿和报告币种。系统内置多币种处理引擎,覆盖全流程货币业务,支持自动重估、再计量和折算。通过SLA子分类账会计实现多会计政策并行处理,满足不同国家会计准则和税制要求。该方案可同时支持本地法定、集团合并及管理分析需求,实现全球财务数据集中管理,提升合规性和运营

金牌架构师 553

Spring 源码:深度解析AOP源码配置解析

Spring框架作为Java应用程序开发中最受欢迎的框架之一,其AOP(面向切面编程)功能是其核心之一。通过AOP,开发人员可以将横切关注点(如日志记录、事务管理等)与核心业务逻辑分离,从而提高代码的模块化和可维护性。深入探讨了Spring AOP的源码配置,着重分析了如何通过配置实现AOP的相关功能。通过对Spring AOP源码配置的深度解析,帮助读者更加全面地理解了AOP在Spring框架中的应用和实现方式,为进一步学习和应用Spring AOP提供了有力的指导和参考。

忆~遂愿的博客 3712

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Spring中AOP相关的API及源码解析,原来AOP是这样子的

Spring中AOP相关的API及源码解析 本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 谈谈Spring中的对象跟Bean,你知道Spring怎么创建对象的吗? 这篇文章,我们来谈一谈Spring中的属性注入 推荐阅读: Spring官网阅读 | 总结篇 Spring杂谈 本系列文章将会带你一行行的将Spring的源码吃透,推荐阅读的文章是阅读源码的基础! 因为本文会涉及到动态代理的相关内容,如果对动态代理不

做一个认真的程序员 1万+

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Spring AOP源码详细解析

一 . 以下是bean的初始化过程: 注意: 先明白beanPostProcessor的作用,才能够明白aop的加载时机 在bean实例化完成之前和完成之后分别会自动BeanPostProcessor接口的postProcessBeforeInitialization和postProcessAfterInitialization方法。 二: 介绍一些Spring Aop中一些核心类,大致分为三类: advisorCreator,继承 spring ioc的扩展接口 beanPos...

pengjianglilive的专栏 3678

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Spring源码解析(九):AOP源码之@Aspect所有相关注解解析

AOP是一种思想,它的实现主要有Spring AOP和AspectJspring AOP底层实现是jdk和cglib动态代理运行期织入借助了AspectJ的语法,即使用了@Aspect @Before @Pointcut等注解来实现AspectJ主要原理是用asm做字节码替换来达到AOP的目的,需要使用专门的编译器ajc编译期、编译期后、类加载期都可以织入AnnotationAwareAspectJAutoProxyCreator主要类图AOP的操作流程都在类中添加注解由@Import注解导入而来。

从基础到源码解析的学习记录 1154

10. Spring AOP源码解析

10 Spring AOP源码解析 目录 10 Spring AOP源码解析 Pt1 Spring AOP基础知识 Pt1.1 AOP核心概念 Pt1.2 AOP切点配置规则 (1) execution (2) within (3) args Pt2 Spring AOP使用示例 Pt2.1 AOP日志(XML) pom.xml spring.xml配置AOP信息 加载spring.xml 定义切面 定义Controller 运行Controller Pt2.2 JDBC(

Java是世界上最好的语言 1485

Spring-Aop源码解析(一)

本文主要讲解spring实现aop的相关源码学习教程,以aop.xml配置文件的方式为例,讲解如何将配置文件的标签解析成bean定义信息,存放到beanfactory中。以及advisor的bean定义信息以及实例化的过程;对哪些类进行代理,以及判断依据是什么。。。。。。

qq_37200262的博客 974

【Spring AOP 源码解析】彻底搞懂 AOP 是如何执行的

Spring 在真正的通过反射去执行实际调用的方法之前,会有一个名为 **`intercept()`** 的方法,执行一些拦截的逻辑;我们构造的这些切面方法实际上就是在这部分中执行的;Spring 在创建 Bean 的时候会根据 AOP 注解生成一个由一组 interceptor 组成的链式结构,然后在调用实际方法之前,通过循环的方式按照顺序去执行这些 interceptor 中的代码,这样就在合适的时机去执行了合适的代码。

kkq的博客 1366

9.Spring AOP源码解析

就是我们前面看到的三个不同优先等级的AutoProxyCreator。

RubyWinner的博客 841

Spring AOP 源码解析

之前写过 IOC 的源码分析,那篇文章真的有点长,看完需要点耐心。很多读者希望能写一写 Spring AOP 的源码分析文章,这样读者看完 IOC + AOP 也就对 Spring 会有比较深的理解了。今天终于成文了,可能很多读者早就不再等待了,不过主要为了后来者吧。 本文不会像 IOC 源码分析那篇文章一样,很具体地分析每一行 Spring AOP 的源码,目标读者是已经知道 Spring IOC 源码是怎么回事的读者,因为 Spring AOP 终归是依赖于 IOC 容器来管理的。 阅读建议:1、先

赶路人儿 1831

Spring AOP源码(1)—<aop:config/>AOP配置标签解析【一万字】

基于最新Spring 5.x,对Spring AOP中的<aop:config/>标签的解析源码进行了详细分析,这是Spring AOP源码的入口!

终生学习践行者 5902

Spring AOP源码分析(二):AOP的三种配置方式与内部解析实现

AOP配置 在应用代码中,可以通过在spring的XML配置文件applicationContext.xml或者基于注解方式来配置AOP。 AOP配置的核心元素为:advice,pointcut,advisor,其中advice用于声明辅助方法,pointcut用于定义需要该辅助功能的类或方法集合,advisor则是将两者结合起来,在spring的IOC容器启动时,为pointcut匹配的类生成...

源码之下,了无秘密 4653
上一篇: Spring IoC 源码导读
下一篇: 最通俗易懂的短链接原理讲解
留兰香丶
博客等级 码龄9年 391粉丝 187原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值