Spring Aop之Advisor解析

Spring Aop(八)——advisor标签 8 advisor标签advisor标签是需要定义在aspect标签里面的,其作用与aspect类似,可以简单的把它理解为一个特殊的切面,用于把一个Advice和一个Pointcut组合起来。一个advisor标签对应的就是一个Advisor接口的实现类,默认是DefaultBeanFactoryPointcutAdvisor实现。其使用的基本语法类似如下这样。<aop:config> <a 阅读详情

文章转载于:https://zhuanlan.zhihu.com/p/44094896

 

在上文Spring Aop之Target Source详解中,我们讲解了Spring是如何通过封装Target Source来达到对最终获取的目标bean进行封装的目的。其中我们讲解到,Spring Aop对目标bean进行代理是通过AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization()进行的,Spring Aop的代理主要分为三个步骤:获取所有的Advisor,过滤可应用到当前bean的Adivsor和使用Advisor为当前bean生成代理对象。本文主要对这三步中的第一步获取所有的Advisor进行讲解。

1. 骨架方法

首先我们看看postProcessAfterInitialization()方法的实现:

public Object postProcessAfterInitialization(@Nullable Object bean, 
       String beanName) throws BeansException {
    if (bean != null) {
        // 获取当前bean的key:如果beanName不为空,则以beanName为key,如果为FactoryBean类型,
        // 前面还会添加&符号,如果beanName为空,则以当前bean对应的class为key
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        // 判断当前bean是否正在被代理,如果正在被代理则不进行封装
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            // 对当前bean进行封装
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

从上述代码可以看出,对目标bean的封装是主要是通过wrapIfNecessary()方法进行的,该方法就是Spring对目标bean进行代理的骨架方法。如下是该方法的实现:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 判断当前bean是否在TargetSource缓存中存在,如果存在,则直接返回当前bean。这里进行如此判断的
    // 原因是在上文中,我们讲解了如何通过自己声明的TargetSource进行目标bean的封装,在封装之后其实
    // 就已经对封装之后的bean进行了代理,并且添加到了targetSourcedBeans缓存中。因而这里判断得到
    // 当前缓存中已经存在当前bean,则说明该bean已经被代理过,这样就可以直接返回当前bean。
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }

    // 这里advisedBeans缓存了已经进行了代理的bean,如果缓存中存在,则可以直接返回
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }

    // 这里isInfrastructureClass()用于判断当前bean是否为Spring系统自带的bean,自带的bean是
    // 不用进行代理的;shouldSkip()则用于判断当前bean是否应该被略过
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        // 对当前bean进行缓存
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // 获取当前bean的Advices和Advisors
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        // 对当前bean的代理状态进行缓存
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 根据获取到的Advices和Advisors为当前bean生成代理对象
        Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, 
            new SingletonTargetSource(bean));
        // 缓存生成的代理bean的类型,并且返回生成的代理bean
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

在上述骨架方法中,Spring主要进行了三件事:

  • 判断当前bean是否已经生成过代理对象,或者是否是应该被略过的对象,是则直接返回,否则进行下一步;
  • 获取当前bean的Advisors和Advices,如果当前bean不需要代理,则返回DO_NOT_PROXY;
  • 通过生成的Advisors和Advices为目标bean生成代理对象。

关于上述骨架方法,这里需要说明两个点:

  • shouldSkip()方法中对当前bean判断是否应该略过时,其主要做了两件事:a. 为当前bean生成需要代理的Advisors;b. 判断生成的Advisor是否为AspectJPointcutAdvisor类型。因而实际上判断略过的过程就是判断是否为AspectJPointcutAdvisor,判断这个类的原因在于Spring Aop的切面和切点的生成也可以通过在xml文件中使用<aop:config/>标签进行。这个标签最终解析得到的Adivsor类型就是`AspectJPointcutAdvisor类型的,因为其在解析<aop:config/>的时候就已经生成了Advisor,因而这里需要对这种类型的Advisor进行略过。这里<aop:config/>也是一种自定义标签,关于其解析过程,读者可以参照本人前面的博文自行阅读器源码;
  • getAdvicesAndAdvisorsForBean()方法就其名称而言是获取Advisors和Advices,但实际上其返回值是一个Advisor的数组。Spring Aop在为目标bean获取需要进行代理的切面逻辑的时候最终得到的是Advisor,这里Advice表示的是每个切面逻辑中使用@Before、@After和@Around等需要织入的代理方法。因为每个代理方法都表示一个Advice,并且每个代理方法最终都会生成一个Advisor,因而Advice和Advisor就本质而言其实没有太大的区别。Advice表示需要织入的切面逻辑,而Advisor则表示将切面逻辑进行封装之后的织入者。

2. 切面的生成

虽然在shouldSkip()方法中会为当前bean生成Advisor,但是在getAdvicesAndAdvisorsForBean()中也还是会获取一次,只不过在第一次生成的时候会将得到的Advisor都进行缓存,因而第二次获取时可以直接从缓存中获取。我们这里还是以getAdvicesAndAdvisorsForBean()方法为准来进行讲解。如下是该方法的源码:

protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, 
        @Nullable TargetSource targetSource) {
    // 为目标bean生成Advisor
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}

我们继续看findEligibleAdvisors()方法:

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 将当前系统中所有的切面类的切面逻辑进行封装,从而得到目标Advisor
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 对获取到的所有Advisor进行判断,看其切面定义是否可以应用到当前bean,从而得到最终需要应用的Advisor
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, 
        beanClass, beanName);
    // 提供的hook方法,用于对目标Advisor进行扩展
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        // 对需要代理的Advisor按照一定的规则进行排序
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

在上述方法中,Spring Aop首先获取到了系统中所有的切面逻辑,并将其封装为了Advisor对象,然后通过遍历Advisor判断哪些Advisor是可以应用到当前bean的,最后将需要织入的Advisor返回。这里我们看看findCandidateAdvisors()的源码:

protected List<Advisor> findCandidateAdvisors() {
    // 找到系统中实现了Advisor接口的bean
    List<Advisor> advisors = super.findCandidateAdvisors();
    if (this.aspectJAdvisorsBuilder != null) {
        // 找到系统中使用@Aspect标注的bean,并且找到该bean中使用@Before,@After等标注的方法,
        // 将这些方法封装为一个个Advisor
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

可以看到,findCandidateAdvisors()主要是通过两种方式获取切面逻辑,一种是在系统中找到实现了Advisor接口的所有类,另一种是在找到系统中使用@Aspect标注的类,并将其切面逻辑封装为Advisor,这两种Advisor都有可能是我们需要进行织入的切面逻辑。这里super.findCandidateAdvisors()方法最终调用的是BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans()方法,我们首先看看该方法的实现:

public List<Advisor> findAdvisorBeans() {
    String[] advisorNames = null;
    synchronized (this) {
        advisorNames = this.cachedAdvisorBeanNames;
        if (advisorNames == null) {
            // 获取当前BeanFactory中所有实现了Advisor接口的bean的名称
            advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this.beanFactory, Advisor.class, true, false);
            this.cachedAdvisorBeanNames = advisorNames;
        }
    }
    if (advisorNames.length == 0) {
        return new LinkedList<>();
    }

    // 对获取到的实现Advisor接口的bean的名称进行遍历
    List<Advisor> advisors = new LinkedList<>();
    for (String name : advisorNames) {
        // isEligibleBean()是提供的一个hook方法,用于子类对Advisor进行过滤,这里默认返回值都是true
        if (isEligibleBean(name)) {
            // 如果当前bean还在创建过程中,则略过,其创建完成之后会为其判断是否需要织入切面逻辑
            if (this.beanFactory.isCurrentlyInCreation(name)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Skipping currently created advisor '" + name + "'");
                }
            } else {
                try {
                    // 将当前bean添加到结果中
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
                } catch (BeanCreationException ex) {
                    // 对获取过程中产生的异常进行封装
                    Throwable rootCause = ex.getMostSpecificCause();
                    if (rootCause instanceof BeanCurrentlyInCreationException) {
                        BeanCreationException bce = (BeanCreationException) rootCause;
                        String bceBeanName = bce.getBeanName();
                        if (bceBeanName != null && 
                            this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("Skipping advisor '" + name + 
                                    "' with dependency on currently created bean: " 
                                    + ex.getMessage());
                            }
                            continue;
                        }
                    }
                    throw ex;
                }
            }
        }
    }
    return advisors;
}

这里findAdvisorBeans()方法逻辑其实非常简单,其主要是在BeanFactory中找打实现了Advisor接口的类,然后通过hook方法判断子类是否需要对Advisor进行过滤,最后将过滤之后的Advisor返回。

接下来我们看看BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors()的实现:

public List<Advisor> buildAspectJAdvisors() {
    List<String> aspectNames = this.aspectBeanNames;
    if (aspectNames == null) {
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                List<Advisor> advisors = new LinkedList<>();
                aspectNames = new LinkedList<>();
                // 获取当前BeanFactory中所有的bean
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    this.beanFactory, Object.class, true, false);
                // 对获取到的所有bean进行循环遍历
                for (String beanName : beanNames) {
                    // 判断当前bean是否为子类定制的需要过滤的bean
                    if (!isEligibleBean(beanName)) {
                        continue;
                    }

                    // 获取当前遍历的bean的Class类型
                    Class<?> beanType = this.beanFactory.getType(beanName);
                    if (beanType == null) {
                        continue;
                    }

                    // 判断当前bean是否使用了@Aspect注解进行标注
                    if (this.advisorFactory.isAspect(beanType)) {
                        aspectNames.add(beanName);

                        // 对于使用了@Aspect注解标注的bean,将其封装为一个AspectMetadata类型。
                        // 这里在封装的过程中会解析@Aspect注解上的参数指定的切面类型,如perthis
                        // 和pertarget等。这些被解析的注解都会被封装到其perClausePointcut属性中
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);
                        // 判断@Aspect注解中标注的是否为singleton类型,默认的切面类都是singleton
                        // 类型
                        if (amd.getAjType().getPerClause().getKind() == 
                            PerClauseKind.SINGLETON) {
                            // 将BeanFactory和当前bean封装为MetadataAwareAspect-
                            // InstanceFactory对象,这里会再次将@Aspect注解中的参数都封装
                            // 为一个AspectMetadata,并且保存在该factory中
                            MetadataAwareAspectInstanceFactory factory =
                                new BeanFactoryAspectInstanceFactory(this.beanFactory, 
                                    beanName);
                            // 通过封装的bean获取其Advice,如@Before,@After等等,并且将这些
                            // Advice都解析并且封装为一个个的Advisor
                            List<Advisor> classAdvisors 
                                this.advisorFactory.getAdvisors(factory);
                            // 如果切面类是singleton类型,则将解析得到的Advisor进行缓存,
                            // 否则将当前的factory进行缓存,以便再次获取时可以通过factory直接获取
                            if (this.beanFactory.isSingleton(beanName)) {
                                this.advisorsCache.put(beanName, classAdvisors);
                            } else {
                                this.aspectFactoryCache.put(beanName, factory);
                            }
                            advisors.addAll(classAdvisors);
                        } else {
                            // 如果@Aspect注解标注的是perthis和pertarget类型,说明当前切面
                            // 不可能是单例的,因而这里判断其如果是单例的则抛出异常
                            if (this.beanFactory.isSingleton(beanName)) {
                                throw new IllegalArgumentException("Bean with name '" 
                                  + beanName + "' is a singleton, but aspect "
                                  + "instantiation model is not singleton");
                            }

                            // 将当前BeanFactory和切面bean封装为一个多例类型的Factory
                            MetadataAwareAspectInstanceFactory factory =
                                new PrototypeAspectInstanceFactory(this.beanFactory, 
                                  beanName);
                            // 对当前bean和factory进行缓存
                            this.aspectFactoryCache.put(beanName, factory);
                            advisors.addAll(this.advisorFactory.getAdvisors(factory));
                        }
                    }
                }
                this.aspectBeanNames = aspectNames;
                return advisors;
            }
        }
    }

    if (aspectNames.isEmpty()) {
        return Collections.emptyList();
    }

    // 通过所有的aspectNames在缓存中获取切面对应的Advisor,这里如果是单例的,则直接从advisorsCache
    // 获取,如果是多例类型的,则通过MetadataAwareAspectInstanceFactory立即生成一个
    List<Advisor> advisors = new LinkedList<>();
    for (String aspectName : aspectNames) {
        List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
        // 如果是单例的Advisor bean,则直接添加到返回值列表中
        if (cachedAdvisors != null) {
            advisors.addAll(cachedAdvisors);
        } else {
            // 如果是多例的Advisor bean,则通过MetadataAwareAspectInstanceFactory生成
            MetadataAwareAspectInstanceFactory factory = 
                this.aspectFactoryCache.get(aspectName);
            advisors.addAll(this.advisorFactory.getAdvisors(factory));
        }
    }
    return advisors;
}

对于通过@Aspect注解获取切面逻辑的方法,这里的逻辑也比较简单,Spring首先会过滤得到BeanFactory中所有标注有@Aspect的类,然后对该注解参数进行解析,判断其环绕的目标bean是单例的还是多例的。如果是单例的,则直接缓存到advisorsCache中;如果是多例的,则将生成Advisor的factory进行缓存,以便每次获取时都通过factory获取一个新的Advisor。上述方法中主要是对@Aspect注解进行了解析,我们前面讲过,Spring Aop的Advisor对应的是Advice,而每个Advice都是对应的一个@Before或者@After等标注方法的切面逻辑,这里对这些切面逻辑的解析过程就在上述的advisorFactory.getAdvisors(factory)方法调用中。这里我们看看该方法的实现:

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    // 获取当前切面类的Class类型
    Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    // 获取当前切面bean的名称
    String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    // 对当前切面bean进行校验,主要是判断其切点是否为perflow或者是percflowbelow,Spring暂时不支持
    // 这两种类型的切点
    validate(aspectClass);

    // 将当前aspectInstanceFactory进行封装,这里LazySingletonAspectInstanceFactoryDecorator
    // 使用装饰器模式,主要是对获取到的切面实例进行了缓存,保证每次获取到的都是同一个切面实例
    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
        new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

    List<Advisor> advisors = new LinkedList<>();
    // 这里getAdvisorMethods()会获取所有的没有使用@Pointcut注解标注的方法,然后对其进行遍历
    for (Method method : getAdvisorMethods(aspectClass)) {
        // 判断当前方法是否标注有@Before,@After或@Around等注解,如果标注了,则将其封装为一个Advisor
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 
           advisors.size(), aspectName);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    // 这里的isLazilyInstantiated()方法判断的是当前bean是否应该被延迟初始化,其主要是判断当前
    // 切面类是否为perthis,pertarget或pertypewithiin等声明的切面。因为这些类型所环绕的目标bean
    // 都是多例的,因而需要在运行时动态判断目标bean是否需要环绕当前的切面逻辑
    if (!advisors.isEmpty() && 
        lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        // 如果Advisor不为空,并且是需要延迟初始化的bean,则在第0位位置添加一个同步增强器,
        // 该同步增强器实际上就是一个BeforeAspect的Advisor
        Advisor instantiationAdvisor = new 
            SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
        advisors.add(0, instantiationAdvisor);
    }

    // 判断属性上是否包含有@DeclareParents注解标注的需要新添加的属性,如果有,则将其封装为一个Advisor
    for (Field field : aspectClass.getDeclaredFields()) {
        Advisor advisor = getDeclareParentsAdvisor(field);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    return advisors;
}

在上述getAdvisors()方法中,Spring会遍历当前切面类所有的方法,包括父类和父接口的方法,找到其中没有使用@Pointcut注解标注的方法,然后对找到的方法进行遍历,将其封装为一个Advisor。这里我们继续看封装为Advisor的方法:

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory 
        aspectInstanceFactory, int declarationOrderInAspect, String aspectName) {

    // 校验当前切面类是否使用了perflow或者percflowbelow标识的切点,Spring暂不支持这两种切点
    validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

    // 获取当前方法中@Before,@After或者@Around等标注的注解,并且获取该注解的值,将其
    // 封装为一个AspectJExpressionPointcut对象
    AspectJExpressionPointcut expressionPointcut = getPointcut(
       candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    if (expressionPointcut == null) {
        return null;
    }

    // 将获取到的切点,切点方法等信息封装为一个Advisor对象,也就是说当前Advisor包含有所有
    // 当前切面进行环绕所需要的信息
    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, 
        candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, 
        aspectName);
}

到这里Spring才将@Before,@After或@Around标注的方法封装为了一个Advisor对象。需要说明的是,这里封装成的Advisor对象只是一个半成品。所谓的半成品指的是此时其并没有对切点表达式进行解析,其还只是使用一个字符串保存在AspectJExpressionPointcut对象中,只有在真正使用当前Advice逻辑进行目标bean的环绕的时候才会对其进行解析。

3. 小结

本文主要讲解了Spring是如何获取所有的Advisor的,即首先获取BeanFactory中所有实现了Advisor接口的bean,然后获取BeanFactory中所有标注了@Aspect注解的bean,解析该bean中的所有的切面逻辑,并且封装为一个个Advisor,这两种方式得到的Advisor都有可能是最终会应用到目标bean上的切面逻辑。需要注意的是,这里获取到的Advisor并没有对切点表达式进行解析,实际的解析过程是在判断当前bean是否可以应用到目标bean时进行的。这也是一个小小的优化,因为解析切点表达式的过程是一个比较复杂的过程。

AOP Advice,Pointcut,Joinpoint和Advisor 定义:Advice是一个接口,是AOP中的一个核心概念,表示切面在连接点(程序执行的特定点,如方法的调用或异常的抛出)上执行的操作。用于定义在连接点上执行的增强逻辑。它本身不是连接点,而是在连接点触发时执行的一段代码。作用:Advice用于在方法执行前、执行后、抛出异常时等不同的执行点插入额外的逻辑,类似于AOP中的切面。它可以用于在不修改原始方法的情况下,实现一些横切关注点的功能,比如日志记录、性能监控、事务管理等。是程序执行过程中某个特定的位置,例如方法调用前、调用后或抛出异常后等。 阅读详情

相关推荐

Spring AOP源码解析(一)Advisor获取

一、入口 AOP的Jar包如下如所示: META-INF中是Spring自定义标签的配置文件,对&lt;aop&gt;标签的支持 spring.schemas配置如下,作用是定义&lt;aop&gt;标签的内容(根据不同版本,Spring使用不同的xsd文件来描述): http\://www.springframework.org/schema/aop/spring-aop-2.0....

finalcola的博客 1384

跟着小马哥学系列之 Spring AOP(Advisor 详解)

学好路更宽,钱多少加班。 ——小马哥 简介 大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间《小马哥讲Spring AOP 编程思想》基础上形成的个人一些总结。希望能帮助各位小伙伴, 祝小伙伴早日学有所成。 ...

qq_42419406的博客 3384

思澈sdk-新建lcd

co5300至此有3个同ID的驱动,在co5300xxxx.c的LCD_DRIVER_EXPORT(co5300, LCD_ID, &lcdc_int_cfg, &CO5300_drv, LCD_PIXEL_WIDTH, LCD_PIXEL_HEIGHT, 2);2 在customer\peripherals\Kconfig_lcd中添加如下配置(注意修改的地方有两个LCD_USING_TFT_CO5300_143)5 在该文件中的config LCD_DPI配置项下添加:(这里300为DPI)

gongyuan073的专栏 1380

聊聊spring aop中的advisor组件

在spring aop中,

cyh的博客 7358

【实战】ComfyUI-Impact-Subpack插件安装与UltralyticsDetectorProvider节点修复全流程

本文详细解析了ComfyUI中UltralyticsDetectorProvider节点缺失的原因,并提供了完整的ComfyUI-Impact-Subpack插件安装与修复全流程。核心在于Impact Pack插件架构调整导致节点被拆分至子插件包。指南涵盖手动安装、依赖安全配置、模型文件管理及深度排错步骤,帮助用户彻底解决节点缺失问题,恢复工作流正常运行。

weixin_29290947的博客 437

【C语言笔记初级篇】第一章:C语言快速入门及注意事项

(1)第一个C语言程序 A:利用vs2010写C语言程序 1:按以下步骤新建工程 2:添加源文件,“.c”文件 B:第一个C语言代码 1:以下是基本的C语言程序 2:由于没有设置连接器,所以打印结果没有显示,按照如下步骤链接控制台 (2)数据类型 A:基本数据类型及占用字节 B:一些概念的梳理 概念一:关于计算机的单位 位(bit):计算机通过电路的开关和闭合处理信息,电路通...

快乐江湖的博客 3737

Spring AOP 源码解析:BeanFactoryAspectJAdvisorsBuilder 如何把 AspectJ 切面转换为 Advisor

本文以 spring-reading 仓库中 [spring-aop-beanFactoryAspectJAdvisorsBuilder](https://link.gitcode.com/i/daea9a9d30eafb102c9152e2c7d8d70a) 模块为核心,深入剖析 `BeanFactoryAspectJAdvisorsBuilder` 在 Spring AOP 自动代理链路中的职

gitblog_00212的博客 323

二十一、SAP-库存管理

业务逻辑、功能讲解、图文解析、章节总结

m0_72403327的博客 1808

Spring AOP源码解析:一:Advisor获取流程

Spring AOP源码解析:一:Advisor获取流程一、流程介绍二、主流程源码介绍三、获取增强Advisor 一、流程介绍 Spring AOP 是通过BeanPostProcessor来进行处理的。每当实例化一个Bean时,会通过这个处理器来进行增强。 分为三步。 获取所有的增强器。 1.1 获取所有的beanName,在beanFactory中所有注册的都提取出来。 1.2 遍历找出所有...

weixin_44366439的博客 1102

【AI应用实战-claude】在飞书上接入claudecode进行远程使用(十三)

本文介绍了三种将ClaudeCode接入飞书的方案,包括官方飞书CLI工具(推荐)、cc-connect中转工具和MCP协议集成。官方飞书CLI适合自动化办公场景,通过简单配置即可实现消息发送和文档管理;cc-connect适用于远程调用Claude功能,通过飞书群聊触发响应;MCP协议则适合开发者构建复杂工作流。文章提供了详细的操作步骤,并针对不同使用场景给出了选择建议。

1009

7.26华为OD机试真题 新系统 - 炸弹人的雷区数量 (Java/Py/C/C++/Js/Go)

7.26华为OD机试真题 新系统 - 炸弹人的雷区数量 (Java/Py/C/C++/Js/Go)

算法大师! 790

Spring AOP(三)【源码分析】基于注解的AOP——第1、2步:解析配置、获取目标Advisor

对于注解形式的SpringAOP实现流程,首先解析配置,注册Bean初始化后的回调,然后获取针对于目标Bean的Advisor增强器。在Bean的初始化之后,1.遍历全部带@Aspect注解的Bean,解析相关信息创建Advisor;2.找到用于当前Bean的Advisor:根据ClassFilter和MethodMatcher过滤。

sun_tantan的博客 989

E2B Agent Runtime Sandbox 沙箱技术架构研究

本实现指南基于E2B的技术架构,提供了完整的基于Firecracker和Docker的Agent Runtime Sandbox后端服务实现方案。架构设计:参考E2B的分层架构,实现API层、管理层和虚拟化层Firecracker集成:深度集成Firecracker提供硬件级安全隔离完整功能:支持文件读写、shell执行、浏览器访问等核心功能生产就绪:提供Docker部署、监控、测试和安全配置可扩展性:设计支持水平扩展和高并发场景。

AI天才研究院 743

Spring AOP源码解析:从@Aspect注解到Advisor的完整蜕变之路

Spring AOP是Java工程中实现横切逻辑的基石,而真正驱动代理增强的核心并非注解本身,而是统一的Advisor抽象。Advisor由切入点表达式与增强逻辑组成,容器通过AutoProxyCreator扫描带@Aspect的Bean,经AspectJAdvisorFactory解析为可执行的Advice,并最终编排进方法拦截器链。理解这一从注解到Advisor的转换原理,不仅能解释切面顺序为何由多种因素叠加决定,也能在通知不生效、表达式不匹配、拦截顺序反转等典型故障中快速定位根因。无论是声明式切面还是

weixin_30899023的博客 246

Taro React组件使用(5) —— RuiPasswordInput 密码输入框显示隐藏和清空

初始化时,需要将传入的 value 赋值给当前组件的 value, 不能直接修改 props 的 value;在组件内输出组件内的变量时,最好先判断输出函数是否定义,再输出,否则很容易引起报错。

止于至善 891

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

深入解析Spring AOP中的Advisor技术点

本文深入解析了Spring AOP中Advisor的技术点,重点介绍了Advisor的组成、实现类型、工作流程以及关键技术要点,帮助开发者深入理解和应用Spring AOP的切面机制,提高代码的模块化和维护性。

weixin_45147384的博客 398

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Spring AOP源码解析:@Aspect如何一步步变成Advisor并生效

面向切面编程(AOP)是Spring框架中处理横切逻辑的核心机制,它将日志、权限、事务等公共关注点与业务逻辑解耦。理解AOP的底层原理,关键在于掌握切面(Aspect)、切入点(Pointcut)与通知(Advice)三者的协作,以及代理对象如何通过JDK动态代理或CGLIB生成并拦截方法调用。在实际工程项目中,切面不生效、通知顺序异常、自调用绕过代理等问题频繁出现,背后往往是对Advisor组装链路和拦截器链调度机制缺乏系统认知。从@Aspect注解到Advisor的转化,是Spring AOP自动代理创

weixin_31309419的博客 215

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Spring AOP核心解析:从@Aspect到Advisor的完整链路与实战排障

面向切面编程(AOP)是Spring框架的核心能力之一,它通过将横切逻辑与业务解耦,提升系统可维护性。在实现层面,Spring AOP并非直接处理业务代码,而是依赖Advisor这一统一抽象,将切点与通知绑定为可执行的增强单元。注解驱动的@Aspect声明,需要经过切面发现、通知解析和代理创建三个阶段,最终生成动态代理对象。理解从@Aspect到Advisor的转换链路,对排查切面不生效、通知重复执行等常见问题至关重要。该机制广泛应用于日志记录、权限校验、事务管理等场景,工程师掌握其解析流程,能更好地设计切

weixin_31528001的博客 186

Spring Aop源码解析(一)------ Advisor的生成

文章目录aop的开启Advisor的生成 aop的开启   直接看到EnableAspectJAutoProxy注解,导入了AspectJAutoProxyRegistrar类 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { /**

qwerty的博客 578

Spring AOP配置原理:Advisor与XML方式及动态代理机制全解析

面向切面编程(AOP)是Spring框架中处理横切逻辑的基础机制,它通过切点与通知将日志、事务、权限等通用逻辑从业务代码中解耦。理解AOP的底层原理,关键在于掌握切点表达式、通知类型以及代理对象的生成过程。Spring AOP提供了多种配置方式,其中Advisor方式以编程式组装切面,XML方式通过标签声明切面,两者在运行时最终都统一为Advisor实例,并交由JDK动态代理或CGLIB动态代理生成代理对象。代理方式的选择直接决定切面是否生效,也与常见的“切面不生效”“类型转换异常”等问题密切相关。在实际项

weixin_32822843的博客 238

Spring AOP切面配置:Advisor与XML方式原理解析与实战对比

面向切面编程(AOP)是Spring框架中实现横切逻辑解耦的关键机制,理解Pointcut、Advice与Advisor三者之间的关系,是掌握Spring AOP原理的基石。Advisor作为承载切入点与通知的最小切面单元,与基于XML的aop:config声明式配置,在底层其实共享同一条代理生成与拦截器调用链。文章从动态代理原理、ProxyFactory装配、BeanPostProcessor自动代理等角度入手,剖析两种配置路径各自的执行链路,并结合权限校验、事务增强等典型业务场景,对比编程式Adviso

weixin_29574585的博客 215

【小家Spring】Spring AOP之Advisor、PointcutAdvisor、IntroductionAdvisor、IntroductionInterceptor(引介增强)

前言 上篇文章:【小家Spring】Spring AOP核心类Pointcut解析,对PointcutExpression切点表达式解析原理分析(以AspectJExpressionPointcut为例) 讲到了很多的Pointcut,以及各自的使用场景。 而Advisor是Pointcut以及Advice的一个结合,有着非常深的联系,因此本文主要扫盲一下Advisor Advisor介绍 Adv...

架构师:通透,才能写出好代码! 1万+

Spring高手之路22——AOP切面类的封装与解析

本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。

卓越无关环境,保持空杯心态——靡不有初,鲜克有终 1万+

Spring AOP源码分析篇二:AnnotationAwareAspectJAutoProxyCreator解析并获取advisor、切点pointcut

在上篇文章中,Spring AOP源码分析篇一:@EnableAspectJAutoProxy的来龙去脉讲述了AOP的开端,其实就是注册了的beanDefinition到容器中,并且在文章结尾处还给出了这个类的继承关系,这个类和他的父类们极为重要,负责把切面类bean的通知(advice)找出来,并用这些通知们生成代理,本文主要围绕他们去开展。老规矩,先祭出流程图看不清没关系,奉上高清链接aop创建动态代理流程| ProcessOn免费在线作图,在线流程图,在线思维导图Spring AOP流程。

weixin_42054506的博客 1104
上一篇: Spring中的5种Aop常见应用方式(扫描注解方式)
下一篇: ByteArrayOutputStream或ByteArrayInputStream是可以不关闭的
ArtisticProgramming
博客等级 码龄8年 1粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值