Spring AOP 总结二

向您生动讲解Spring AOP 源码(2) 前言 往期文章: Spring IoC - Spring IoC 的设计 Spring IoC - IoC 容器初始化 源码解析 Spring IoC - 依赖注入 源码解析 向您生动地讲解Spring AOP 源码(1) 在上一章向您生动地讲解Spring AOP 源码(1)中,作者介绍了【开启AOP自动代理的玄机】和【自动代理的触发时机】。 在本章中,作者会向您介绍,Spring AOP ... 阅读详情

前面说过:AOP是一种编程思想,用于将程序中的横切关注点(如事务、日志)从业务逻辑代码中分离出来,以提高代码的可重用性和可维护性。Spring框架对其进行了实现。在Spring中AOP是通过代理模式实现的,即在运行时动态的生成一个代理,这个代理类会拦截目标对象的方法调用,并在方法执行前后添加响应的横切逻辑。

通过这一段话,我们只能知道Spring框架使用动态代理技术对AOP进行了实现。那Spring究竟是怎么实现的呢?下面就根据源码一步步地揭开Spring AOP的神秘面纱吧。在开始跟踪之前,先来看一个问题吧:假设现在没有实现AOP的Spring框架,公司领导又点名要你给系统增加日志功能,作为开发者你会怎么做(需要说明的是要添加日志的接口非常多,并且这个日志要足够灵活,能够支持后面其他同事开发的新接口。那该怎么高效、安全的实现这个需求呢?答案肯定是AOP!)。思路大概是这样的(这里有点事后诸葛亮,不过还是想通过这个让大家有个基本的认识,以便后面跟踪Spring源码时能够快速理解。该思路参照了字符串搜索表达式,同时用到了反射和动态代理):

  1. 配置匹配模式,即匹配将被增强的方法(即目标方法)
  2. 编写增强方法,即要对目标方法做的增强逻辑,比如本例中的日志打印逻辑
  3. 为目标创建代理,然后使用该代理

参照上述两点,落地开发的详细步骤为:

  1. 匹配模式解析,即将该匹配模式保存下来,以便后面匹配时使用
  2. 被增强方法匹配逻辑,即用配置的匹配模式找到要被增强的类或方法,并将其存储在Map中
  3. 增强方法解析及增强方法与匹配模式关系处理,即将增强方法解析出来,并为该增强方法指定一定的匹配模式
  4. 为目标方法创建一个代理,然后在该代理类相关方法的前后设置相关增强方法
  5. 调用代理调用目标方法

这里要注意一下:被增强的方法,即目标方法,是处理实际业务的方法(比如上一节TransferService类中的check(…)方法);匹配模式,即切入点,它是一个字符串表达式,用于匹配合适的目标方法(比如上一节CustomerAspect中的pointcut(…)方法);增强方法,即切面,是对目标方法的扩展,比如日志打印、事务等(比如上一节CustomerAspect类中的around(…)方法、before(…)方法、after(…)方法)。

下面我们从@EnableAspectJAutoProxy注解开始跟踪。该注解详细实现代码中有一个注解@Import(AspectJAutoProxyRegistrar.class),通过该注解系统会自动向Spring容器中注入一个类型为AnnotationAwareAspectJAutoProxyCreator的对象。我们先看一下这两个注解的代码实现:

 从这里继续向下跟踪会看到如下图所示的代码:

前面提到过,这里会向容器中注入AnnotationAwareAspectJAutoProxyCreator对象,该类的继承结构如下图所示: 

 从这幅图可以看到AbstractAutoProxyCreator继承了BeanPostProcessor接口。该接口中主要定义了两个方法:

default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
}
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
}

由此可知继承该接口的实现类的主要作用是在注册到Spring中的Bean的初始化前后做一些处理,比如本节要讲的代理对象就是在postProcessAfterInitialization()方法中创建的。接下来主要看一下AbstractAutoProxyCreator类中的postProcessAfterInitialization()方法的代码,其代码如下所示:

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
       Object cacheKey = getCacheKey(bean.getClass(), beanName);
       if (this.earlyBeanReferences.remove(cacheKey) != bean) {
// 主要关注这里
          return wrapIfNecessary(bean, beanName, cacheKey);
       }
    }
    return bean;
}

在上面代码中我们主要关注wrapIfNecessary()方法。该方法的代码如下所示:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
       return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
       return bean;
    }
    // 重点关注这个 shouldSkip() 方法,该方法最终会调用BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors()以解析@Aspect注解修饰的类,其中用@Around、@After、@Before等注解修饰的方法会被解析
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
       this.advisedBeans.put(cacheKey, Boolean.FALSE);
       return bean;
    }

    // Create proxy if we have advice.
    // 这段代码的主要逻辑是提取适用该对象的Advice和Advisor。
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
       this.advisedBeans.put(cacheKey, Boolean.TRUE);
       Object proxy = createProxy(
             bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
       this.proxyTypes.put(cacheKey, proxy.getClass());
       return proxy;
    }

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

对于这个方法我想按照以下顺序梳理:解析(主要解析系统中配置的切面和切点)、创建代理(将符合切点的方法和切面进行组合,并用代理对象包装)。

1 解析

这里主要梳理Spring如何解析用@Aspect修饰的类以及@Around、@After、@Before等注解修饰的方法。下面首先看一下AspectJAwareAdvisorAutoProxyCreator#shouldSkip(Class<?> beanClass, String beanName)方法,其源码如下所示:

@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // TODO: Consider optimization by caching the list of the aspect names
    // 该方法的主要作用是查找所有候选的Advisor
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    for (Advisor advisor : candidateAdvisors) {
       if (advisor instanceof AspectJPointcutAdvisor pointcutAdvisor &&
             pointcutAdvisor.getAspectName().equals(beanName)) {
          return true;
       }
    }
    return super.shouldSkip(beanClass, beanName);
}

这里主要看findCandidateAdvisors()方法,该方法的源码如下所示(注意这个源码位于AspectJAwareAdvisorAutoProxyCreator类中):

protected List<Advisor> findCandidateAdvisors() {
    Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
    return this.advisorRetrievalHelper.findAdvisorBeans();
}

由于Spring容器启动时注入的实际类型为AnnotationAwareAspectJAutoProxyCreator,所以AspectJAwareAdvisorAutoProxyCreator#shouldSkip(Class<?> beanClass, String beanName)中的List<Advisor> candidateAdvisors = findCandidateAdvisors()最终调用的是AnnotationAwareAspectJAutoProxyCreator中的findCandidateAdvisors()方法,其源码如下所示:

@Override
protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules.
    List<Advisor> advisors = super.findCandidateAdvisors();
    // Build Advisors for all AspectJ aspects in the bean factory.
    if (this.aspectJAdvisorsBuilder != null) {
       // 重点关注这里
       advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

这里主要看this.aspectJAdvisorsBuilder.buildAspectJAdvisors()这段代码,该方法位于BeanFactoryAspectJAdvisorsBuilder类中,其源码如下所示:

public List<Advisor> buildAspectJAdvisors() {
    List<String> aspectNames = this.aspectBeanNames;

    if (aspectNames == null) {
       synchronized (this) {
          aspectNames = this.aspectBeanNames;
          if (aspectNames == null) {
             List<Advisor> advisors = new ArrayList<>();
             aspectNames = new ArrayList<>();
             String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                   this.beanFactory, Object.class, true, false);
             for (String beanName : beanNames) {
                if (!isEligibleBean(beanName)) {
                   continue;
                }
                // We must be careful not to instantiate beans eagerly as in this case they
                // would be cached by the Spring container but would not have been weaved.
                Class<?> beanType = this.beanFactory.getType(beanName, false);
                if (beanType == null) {
                   continue;
                }
                if (this.advisorFactory.isAspect(beanType)) {
                   aspectNames.add(beanName);
                   AspectMetadata amd = new AspectMetadata(beanType, beanName);
                   if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                      MetadataAwareAspectInstanceFactory factory =
                            new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                      List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                      if (this.beanFactory.isSingleton(beanName)) {
                         this.advisorsCache.put(beanName, classAdvisors);
                      }
                      else {
                         this.aspectFactoryCache.put(beanName, factory);
                      }
                      advisors.addAll(classAdvisors);
                   }
                   else {
                      // Per target or per this.
                      if (this.beanFactory.isSingleton(beanName)) {
                         throw new IllegalArgumentException("Bean with name '" + beanName +
                               "' is a singleton, but aspect instantiation model is not singleton");
                      }
                      MetadataAwareAspectInstanceFactory factory =
                            new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                      this.aspectFactoryCache.put(beanName, factory);
                      advisors.addAll(this.advisorFactory.getAdvisors(factory));
                   }
                }
             }
             this.aspectBeanNames = aspectNames;
             return advisors;
          }
       }
    }
    // 下面这段在跟踪的时候没走,所以以下代码暂不梳理
    if (aspectNames.isEmpty()) {
       return Collections.emptyList();
    }
    List<Advisor> advisors = new ArrayList<>();
    for (String aspectName : aspectNames) {
       List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
       if (cachedAdvisors != null) {
          advisors.addAll(cachedAdvisors);
       }
       else {
          MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
          advisors.addAll(this.advisorFactory.getAdvisors(factory));
       }
    }
    return advisors;
}

从上述代码可以知道,这段代码会遍历Spring容器中注册的所有beanName,然后判断该bean是否被@Aspect注解修饰,如果是则继续解析,否则跳过,具体如下图所示:

上述代码中的List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory)是真正解析的入口。其代码(位于ReflectiveAspectJAdvisorFactory类中)如下所示:

@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    validate(aspectClass);

    // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    // so that it will only instantiate once.
    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
          new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

    List<Advisor> advisors = new ArrayList<>();
    for (Method method : getAdvisorMethods(aspectClass)) {
       // Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
       // to getAdvisor(...) to represent the "current position" in the declared methods list.
       // However, since Java 7 the "current position" is not valid since the JDK no longer
       // returns declared methods in the order in which they are declared in the source code.
       // Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
       // discovered via reflection in order to support reliable advice ordering across JVM launches.
       // Specifically, a value of 0 aligns with the default value used in
       // AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
       Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
       if (advisor != null) {
          advisors.add(advisor);
       }
    }

    // If it's a per target aspect, emit the dummy instantiating aspect.
    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
       Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
       advisors.add(0, instantiationAdvisor);
    }

    // Find introduction fields.
    for (Field field : aspectClass.getDeclaredFields()) {
       Advisor advisor = getDeclareParentsAdvisor(field);
       if (advisor != null) {
          advisors.add(advisor);
       }
    }

    return advisors;
}

该方法主要做了两件事:1.解析@Aspect注解修饰的类中被@Around、@After、@Before修饰的方法;2.解析@Aspect注解修饰的类中的字段。第一步解析调用的是ReflectiveAspectJAdvisorFactory类中的getAdvisor()方法,该方法主要做了下面几件事:

  1. 校验(个人理解就是校验当前Bean对应的类是否被@Aspect注解修饰)
  2. 解析切入点,即AspectJExpressionPointcut,也就是@Around等注解中指定的切入点
  3. 创建InstantiationModelAwarePointcutAdvisorImpl对象,这里会创建实际的通知类型,即Advice

getAdvisor()方法的主要代码如下所示:

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

    validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

    AspectJExpressionPointcut expressionPointcut = getPointcut(
          candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    if (expressionPointcut == null) {
       return null;
    }

    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
          this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

接下来继续看InstantiationModelAwarePointcutAdvisorImpl构造方法的代码,如下所示:

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
       Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
       MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

    this.declaredPointcut = declaredPointcut;
    this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
    this.methodName = aspectJAdviceMethod.getName();
    this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
    this.aspectJAdviceMethod = aspectJAdviceMethod;
    this.aspectJAdvisorFactory = aspectJAdvisorFactory;
    this.aspectInstanceFactory = aspectInstanceFactory;
    this.declarationOrder = declarationOrder;
    this.aspectName = aspectName;

    if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
       // Static part of the pointcut is a lazy type.
       Pointcut preInstantiationPointcut = Pointcuts.union(
             aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

       // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
       // If it's not a dynamic pointcut, it may be optimized out
       // by the Spring AOP infrastructure after the first evaluation.
       this.pointcut = new PerTargetInstantiationModelPointcut(
             this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
       this.lazy = true;
    }
    else {
       // A singleton aspect.
       this.pointcut = this.declaredPointcut;
       this.lazy = false;
       this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
    }
}

主要关注这段代码的最后一行,即调用instantiateAdvice(AspectJExpressionPointcut pointcut)方法的这行,该方法源码如下所示:

private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
    Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
          this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    return (advice != null ? advice : EMPTY_ADVICE);
}

该方法最终会调用AspectJAdvisorFactory类的getAdvice()方法,其源码如下所示:

@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
       MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

    Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    validate(candidateAspectClass);

    AspectJAnnotation aspectJAnnotation =
          AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
       return null;
    }

    // If we get here, we know we have an AspectJ method.
    // Check that it's an AspectJ-annotated class
    if (!isAspect(candidateAspectClass)) {
       throw new AopConfigException("Advice must be declared inside an aspect type: " +
             "Offending method '" + candidateAdviceMethod + "' in class [" +
             candidateAspectClass.getName() + "]");
    }

    if (logger.isDebugEnabled()) {
       logger.debug("Found AspectJ method: " + candidateAdviceMethod);
    }

    AbstractAspectJAdvice springAdvice;

    switch (aspectJAnnotation.getAnnotationType()) {
       case AtPointcut -> {
          if (logger.isDebugEnabled()) {
             logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
          }
          return null;
       }
       case AtAround -> springAdvice = new AspectJAroundAdvice(
             candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
       case AtBefore -> springAdvice = new AspectJMethodBeforeAdvice(
             candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
       case AtAfter -> springAdvice = new AspectJAfterAdvice(
             candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
       case AtAfterReturning -> {
          springAdvice = new AspectJAfterReturningAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
          AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
          if (StringUtils.hasText(afterReturningAnnotation.returning())) {
             springAdvice.setReturningName(afterReturningAnnotation.returning());
          }
       }
       case AtAfterThrowing -> {
          springAdvice = new AspectJAfterThrowingAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
          AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
          if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
             springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
          }
       }
       default -> throw new UnsupportedOperationException(
             "Unsupported advice type on method: " + candidateAdviceMethod);
    }

    // Now to configure the advice...
    springAdvice.setAspectName(aspectName);
    springAdvice.setDeclarationOrder(declarationOrder);
    String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    if (argNames != null) {
       springAdvice.setArgumentNamesFromStringArray(argNames);
    }
    springAdvice.calculateArgumentBindings();

    return springAdvice;
}

对于这段代码主要关注下图所示的地方(这里会根据枚举类型创建不同的Advice):

至此Spring AOP解析的步骤都梳理完成了。下面继续看一下解析过程中涉及的两个主要角色吧!它们分别为:Advisor、Advice。Advisor是Spring AOP的顶级接口,上面看到的InstantiationModelAwarePointcutAdvisorImpl就实现了该接口,其包含了通知(Advice)和适用判断的过滤器。考虑到通用性,过滤规则由其子接口定义,比如IntroductionAdvisor和PointcutAdvisor,过滤器用于判断bean是否需要被代理。Advice被称为通知,也即在调用目标方法时我们想要做的处理逻辑,比如处理事务、打印日志等,比如上节示例中提到的前置通知、后置通知和环绕通知等。通过源码也可以知道Spring AOP提供的通知主要有这样几类:AtAround、AtBefore、 AtAfter、AtAfterReturning、AtAfterThrowing。这些都定义在Spring的AspectJAnnotationType枚举中。该枚举的源码如下所示:

protected enum AspectJAnnotationType {
    AtPointcut, AtAround, AtBefore, AtAfter, AtAfterReturning, AtAfterThrowing
}

下图是Spring AOP常见的几种通知的类结构图:

这里要再明确这样一个点:Advisor包含通知(拦截器),是Spring中AOP的顶级接口,不过这个接口实现类中还需要包含一个aop适用判断的过滤器。考虑到通用性,过滤规则由其子接口定义,比如IntroductionAdvisor和PointcutAdvisor,过滤器用于判断bean是否需要被代理。下面两幅图就展示了IntroductionAdvisor、PointcutAdvisor及其子类的类结构。还记得InstantiationModelAwarePointcutAdvisorImpl对象的创建吧!这里再看以下这段代码: 

AspectJExpressionPointcut expressionPointcut = getPointcut(
       candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
    return null;
}
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
       this, aspectInstanceFactory, declarationOrderInAspect, aspectName);

下图为Pointcut接口的实现类AspectJExpressionPointcut的类结构图。Pointcut可以被称作切点,是过滤器的一种实现,用于匹配过滤哪些类或哪些方法需要被切面处理,其实现了ClassFilter和MethodMatcher接口。这个类在定义PointcutAdvisor(比如创建上图InstantiationModelAwarePointcutAdvisorImpl类型对象时,会向其构造方法中传递一个AspectJExpressionPointcut类型的对象)类型的对象时会用到。

从上图可以看出AspectJExpressionPointcut实现了ClassFilter和MethodMatcher接口。其中ClassFilter是限制切入点或引入点与给定目标类集的匹配的筛选器,属于过滤器的一种实现。过滤筛选合适的类,有些类不需要被处理。MethodMatcher是方法匹配器,定义方法匹配规则,也是过滤器的一种实现,其主要用于判断哪些方法需要使用AOP。不知道你有没有注意到,AspectJExpressionPointcut类中有这样一段代码:

看着是不是有些熟悉,还记得Spring AOP第一篇中切入点的定义吗?对,就是@Pointcut("execution(* org.com.chinasofti.springtransaction.service.*.*(..))")注解中的execution。这组定义涉及到了切点的定义,这里就不再梳理了,如果想深入了解配置规则,可以参照下面这篇博客:https://www.cnblogs.com/cunkouzh/p/5844816.html。

2 创建代理

本小节主要梳理Spring AOP代理类的创建过程。代码入口位于AbstractAutoProxyCreator类的wrapIfNecessary(Object bean, String beanName, Object cacheKey)方法中。如下图所示:

接下来主要关注createProxy(Class<?> beanClass, @Nullable String beanName,    @Nullable Object[] specificInterceptors, TargetSource targetSource)方法的处理逻辑,该方法位于AbstractAutoProxyCreator类中,其详细代码如下所示:

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
       @Nullable Object[] specificInterceptors, TargetSource targetSource) {

    return buildProxy(beanClass, beanName, specificInterceptors, targetSource, false);
}

这段代码非常简单,主要是调用AbstractAutoProxyCreator的buildProxy()方法去创建代理,其具体代码如下所示:

private Object buildProxy(Class<?> beanClass, @Nullable String beanName,
       @Nullable Object[] specificInterceptors, TargetSource targetSource, boolean classOnly) {

    if (this.beanFactory instanceof ConfigurableListableBeanFactory clbf) {
       AutoProxyUtils.exposeTargetClass(clbf, beanName, beanClass);
    }

    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);

    if (proxyFactory.isProxyTargetClass()) {
       // Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
       if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
          // Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
          for (Class<?> ifc : beanClass.getInterfaces()) {
             proxyFactory.addInterface(ifc);
          }
       }
    }
    else {
       // No proxyTargetClass flag enforced, let's apply our default checks...
       if (shouldProxyTargetClass(beanClass, beanName)) {
          proxyFactory.setProxyTargetClass(true);
       }
       else {
          evaluateProxyInterfaces(beanClass, proxyFactory);
       }
    }

    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
       proxyFactory.setPreFiltered(true);
    }

    // Use original ClassLoader if bean class not locally loaded in overriding class loader
    ClassLoader classLoader = getProxyClassLoader();
    if (classLoader instanceof SmartClassLoader smartClassLoader && classLoader != beanClass.getClassLoader()) {
       classLoader = smartClassLoader.getOriginalClassLoader();
    }
    return (classOnly ? proxyFactory.getProxyClass(classLoader) : proxyFactory.getProxy(classLoader));
}

通过代码不难看出,其首先创建一个代理工厂对象,即ProxyFactory proxyFactory = new ProxyFactory(),接着从容器中拿到适配指定beanName的Advisor,即前面提到的包含通知和适配过滤器的对象,这里拿到的是一组对象,其实际类型就是前面提到的InstantiationModelAwarePointcutAdvisorImpl类型(这里参照的是前一节的示例),最后调用ProxyFactory类的getProxy()方法创建代理对象。接下来看一下PoxyFactory类的getProxy()方法,其具体代码如下所示:

public Object getProxy(@Nullable ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}

该类会调用其父类ProxyCreatorSupport类的createAopProxy(),其代码如下所示:

protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
       activate();
    }
    return getAopProxyFactory().createAopProxy(this);
}

这个方法(指的是createproxy())先调用本类中的getAopProxyFactory()方法获取AopProxyFactory类型的对象aopProxyFactory(该对象的初始化实在ProxyCreatorSupport类的构造方法中做的,具体如下图所示)

接着这个方法(指的是createproxy())又继续DefaultAopProxyFactory(该类实现了AopProxyFactory接口)类的createAopProxy()方法,其具体代码如下所示:

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
       Class<?> targetClass = config.getTargetClass();
       if (targetClass == null) {
          throw new AopConfigException("TargetSource cannot determine target class: " +
                "Either an interface or a target is required for proxy creation.");
       }
       if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
          return new JdkDynamicAopProxy(config);
       }
       return new ObjenesisCglibAopProxy(config);
    }
    else {
       return new JdkDynamicAopProxy(config);
    }
}

从这段代码可以看到我们常见的JDK动态代理和CGLIB动态代理。根据debug结果,Spring使用CGLIB来创建目标对象的代理对象,即使用ObjenesisCglibAopProxy对象来创建后面的代理对象。注意该类继承了CglibAopProxy类。接着继续回到PoxyFactory类的getProxy()方法中,继续跟踪到getProxy()方法,此时会跳转到CglibAopProxy类的getProxy()方法中,该方法继续调用本类的buildProxy ()方法。该方法源码如下所示:

private Object buildProxy(@Nullable ClassLoader classLoader, boolean classOnly) {
    if (logger.isTraceEnabled()) {
       logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
    }

    try {
       Class<?> rootClass = this.advised.getTargetClass();
       Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

       Class<?> proxySuperClass = rootClass;
       if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
          proxySuperClass = rootClass.getSuperclass();
          Class<?>[] additionalInterfaces = rootClass.getInterfaces();
          for (Class<?> additionalInterface : additionalInterfaces) {
             this.advised.addInterface(additionalInterface);
          }
       }

       // Validate the class, writing log messages as necessary.
       validateClassIfNecessary(proxySuperClass, classLoader);

       // Configure CGLIB Enhancer...
       Enhancer enhancer = createEnhancer();
       if (classLoader != null) {
          enhancer.setClassLoader(classLoader);
          if (classLoader instanceof SmartClassLoader smartClassLoader &&
                smartClassLoader.isClassReloadable(proxySuperClass)) {
             enhancer.setUseCache(false);
          }
       }
       enhancer.setSuperclass(proxySuperClass);
       enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
       enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
       enhancer.setAttemptLoad(true);
       enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));

       Callback[] callbacks = getCallbacks(rootClass);
       Class<?>[] types = new Class<?>[callbacks.length];
       for (int x = 0; x < types.length; x++) {
          types[x] = callbacks[x].getClass();
       }
       // fixedInterceptorMap only populated at this point, after getCallbacks call above
       ProxyCallbackFilter filter = new ProxyCallbackFilter(
             this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset);
       enhancer.setCallbackFilter(filter);
       enhancer.setCallbackTypes(types);

       // Generate the proxy class and create a proxy instance.
       // ProxyCallbackFilter has method introspection capability with Advisor access.
       try {
          return (classOnly ? createProxyClass(enhancer) : createProxyClassAndInstance(enhancer, callbacks));
       }
       finally {
          // Reduce ProxyCallbackFilter to key-only state for its class cache role
          // in the CGLIB$CALLBACK_FILTER field, not leaking any Advisor state...
          filter.advised.reduceToAdvisorKey();
       }
    }
    catch (CodeGenerationException | IllegalArgumentException ex) {
       throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
             ": Common causes of this problem include using a final class or a non-visible class",
             ex);
    }
    catch (Throwable ex) {
       // TargetSource.getTarget() failed
       throw new AopConfigException("Unexpected AOP exception", ex);
    }
}

该方法首先创建了Enhancer对象,然后进行一些属性设置,最后调用createProxyClassAndInstance(enhancer, callbacks))创建对应的代理对象。好了,先到这里吧!先跟大家说声对不起,因为我觉得Spring AOP涉及的知识点和编码逻辑还有很多,认知有限的我,真的无法向大家一一介绍,不过后续我还会根据需要对此知识点进行持续更新,也欢迎大家对文章中的不足提出宝贵的意见。在这里先谢谢了!

Spring——AOP(二)基于XML实现AOP 2基于XML实现AOP XML配置实现AOP:通过XML配置AOP是Spring框架专有的,但由于AspectJ得到越来越多的AOP框架支持,所以通过注解实现AOP将会有更多重用的机会。通过XML配置实现AOP代码如下: CalculatorAspect类: package com.jd.calculator; import org.aspectj.lang.JoinPoint; p... 阅读详情

相关推荐

【论文笔记】Reaching agreement in the presence of faults (EIG)

1 问题定义 2 交互一致性 3 单点故障 m=1 n=4 4 多点故障(n&amp;gt;=3m+1) 计算过程 m=2 n=7 5 n&amp;lt;3m+1不能达成协定 6 带认证的算法 7 总结 这篇论文在1980年发表,是1982年著名的拜占庭将军问题论文的前身。作者Leslie Lamport是2013图灵奖得主,两篇论文引用次数分别为5000+和2000+。该论文提出的算法现在被...

zjwreal 2992

Spring 5.x 源码之旅四十五Aspect注解解析二

Spring 5.x 源码之旅四十五Aspect注解解析二ReflectiveAspectJAdvisorFactory的getAdvisorgetPointcut获取切点表达式AbstractAspectJAdvisorFactory的findAspectJAnnotationOnMethodInstantiationModelAwarePointcutAdvisorImpl构造方法Instan...

王伟王胖胖的博客 793

linux下redhat6.8(理论是都适用)安装oracle12c---详细教程

1、配置yum源 1)、删除Redhat自带的yum: (2)、上传centos的yum包,并按照顺序安装,所需的rpm包通过点击这里获取(放在oracle文件中的centos yum):上传到linux中 进行安装 yum包链接:https://pan.baidu.com/s/1TxciCWEd7d-d4kGoea0L1w 提取码:eufp `` --注意后面两个安装包一起安装 ## 3)、更改系统yum源: 编辑rhel-source.repo文件,将其中的$releas

z931407229的博客 1148

Spring AOP源码学习:创建 AOP 代理

目录 前言 AnnotationAwareAspectJAutoProxyCreator AbstractAutoProxyCreator#postProcessAfterInitialization 代码块1:wrapIfNecessary 代码块2:getAdvicesAndAdvisorsForBean 代码块3:findEligibleAdvisors 代码块4:findAdvisorBeans 代码块5:findCandidateAdvisors 代码块6:buildAspect

程序员囧辉 5201

用Multisim和AD2复刻经典:手把手教你搭建μA741三角波-方波发生器(附完整避坑指南)

本文详细介绍了如何使用Multisim和AD2搭建基于μA741运算放大器的三角波-方波发生器,包括电路原理、Multisim仿真流程、AD2硬件搭建及调试技巧。通过对比理论计算、仿真和实测数据,深入分析器件非理想特性的影响,并提供16个典型问题的解决方案,帮助读者掌握波形发生器的设计原理和工程调试经验。

weixin_28744423的博客 284

AI编程助手Cursor如何革新经济学研究:从计量模型到可视化全流程实战

在数据科学和人工智能技术蓬勃发展的今天,如何高效地将前沿AI工具融入专业领域的研究工作流,成为提升科研效率的关键。其核心原理在于通过自然语言交互,将研究者的专业问题转化为机器可执行的指令,从而实现人机协作的范式转移。这一技术的核心价值在于大幅降低非计算机背景研究者的编程门槛,将精力从繁琐的代码实现中解放出来,更聚焦于学科本身的思想与逻辑。尤其在经济学、金融学等高度依赖数据分析和计量建模的领域,AI编程助手能够快速处理数据清洗、模型估计、可视化及结果解释等任务。具体到应用场景,研究者可以利用结构化提示词工程,

weixin_42531579的博客 295

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

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

qq_42419406的博客 3384

游戏脚本开发避坑:Python调用OP模块实现阴阳师后台操作的5个关键点

本文深入探讨了使用Python调用OP模块开发《阴阳师》后台自动化脚本的5个核心避坑点。重点解析了窗口绑定、后台截图与图像识别、鼠标键盘模拟、脚本稳定性以及性能优化等关键环节的常见问题与实战解决方案,帮助开发者高效实现稳定的游戏后台挂机功能。

u0v1w2x3的博客 588

springAop原理之(二)Advisor、pointcut接口族介绍

​​​​​​​​ Advisor:包含AOP通知的基本接口(在连接点采取的操作)和一个确定建议的适用性的过滤器(例如一个切入点)。这个接口不是供Spring用户使用的,而是允许在支持不同类型的通知时具有通用性。Spring AOP基于通过方法拦截的环绕通知传递,符合AOP联盟拦截API。Advisor接口支持不同类型的建议,如之前和之后的通知,不需要使用拦截实现。 PointcutAdvisor:由切入点驱动的所有Advisor的超级接口。这几乎涵盖了除introduction advisors以外的所有

sinat_33472737的博客 1894

QCM2290 PM-3 如何让mirco-usb支持关机充电

PM4125-3插入type-C触发开机进入关机充电的CC脚中断条件是否可以软件上屏蔽, 做到只通过VBUS中断即可触发进入关机充电模式,达到和PM4125-2的效果一样只要插入micro USB 就可以触发进入关机充电模式。硬件团队提议修改寄存器 SCHG_L_MISC_SYSOK_CFG 0x164A bit[4] 目前修改如下 — a/BOOT.XF.4.1/boot_images/QcomPkg/Library/PmicLib/target/Agatti_pmCocos/psi/pm_confi

墨染天玑的博客 440

H3C交换机命令大全,分模块好记忆!

在深入命令之前,我们先来了解H3C交换机的命令行基础。<H3C>[H3C]常用基础命令如下:这些基础命令是操作H3C交换机的敲门砖,熟练掌握后,我们将按模块深入探讨更具体的配置命令。H3C交换机的命令可以按功能模块分类,包括系统管理、接口配置、VLAN操作、链路聚合、路由配置、安全管理等。

网络技术联盟站 780

详解Spring AOP篇二

详解Spring AOP的核心概念及两种实现方式。

. 5233

32、生物信息学中的符号、缩写及相关概念解析

本文详细解析了生物信息学中常用的符号、缩写及相关概念,涵盖概率理论、函数表示、模型结构、图与集合、维度参数、神经网络、隐藏马尔可夫模型、双向架构、语法系统、系统发育树、微阵列分析以及核方法与支持向量机等多个领域。通过表格和mermaid流程图的形式,系统梳理了各类符号的定义与应用场景,并介绍了常见缩写的全称与意义。文章旨在帮助研究人员准确理解生物信息学中的基础术语,提升对基因表达分析、序列建模、机器学习等技术的理解与应用能力。

rrr55的博客 143

Spring AOP实现浅析 二

​ 紧接上文《Spring AOP实现浅析 一》,本文继续介绍了Spring AOP实现的基础知识,了解了这些,将一步步带你明白Spring AOP实现的由来和历程。

weixin_45749194的博客 884

深度学习工具包 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")

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

实验二 Spring AOP的使用

实验目的: 1.了解AOP的概念和使用 2.理解AOP中的切面以及通知 3.熟悉Spring中两种动态代理方式的区别 4.掌握基于代理类的AOP实现 实验内容: 实验任务1:创建项目,引入相关架包 在IDEA中创建一个名为spring02的Web项目,并将相关架包复制到lib目录,并发布到类路径下(具体操作方法在实验一中已经介绍,这里不详细说明,实验一地址:(29条消息) 实验一:Spriing IOC基本操作_老徐爱吃肉!的博客-优快云博客) 在这里我们需要将本次使用的两个架包也复制到l

qq_35965559的博客 1050

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

(二)Spring AOP

Spring AOP 是基于代理模式实现的,允许开发者将横切关注点(如日志、安全、事务等)提取成独立的切面,并且在不修改目标代码的情况下将其应用到目标方法上。Spring AOP 提供了灵活的通知类型(前置通知、后置通知、返回通知、异常通知、环绕通知)和强大的切入点表达式支持,使得开发者可以灵活地对目标对象进行增强。AOP 在事务管理、性能监控、日志记录等方面广泛应用,极大简化了开发。

qq_50847694的博客 1007

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Spring AOP简介二

一、先了解AOP的相关术语:1.通知(Advice):   通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。 2.切入点(Pointcut)   通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称,Spring中允许我们方便的用正则表达式来指定。(就是指定所有想启用通知的方法,也即指定所有想被通知拦截的方法) 3.连接点(Joinpoint):   程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用

rj042的专栏 817

Spring二:AOP和事务

Spring AOP和事务的介绍以及代码实现,文末附源码,供入门者下载学习

青衫忆笙的博客 3059

Spring AOP理解 二

一、对AOP的初印象 首先先给出一段比较专业的术语(来自百度): 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方 式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个 热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑 的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高 了开发的效率。 然后我们举一个比较容易理

第7维度 - 日常笔记 217

Spring之AOP源码(二)

书接上文 文章目录一、简介1. 前文回顾2. 知识点补充二、ProxyFactory源码分析1. ProxyFactory2. JdkDynamicAopProxy3. ObjenesisCglibAopProxy三、 Spring AOP源码分析 一、简介 1. 前文回顾 前面我们已经介绍了AOP的基本使用方法以及基本原理,但是还没有涉及源码层面,这篇文章就深度分析一下SpringAOP的底层源码。 2. 知识点补充 TargetSource 在我们日常的AOP中,被代理对象就是Bean对象,是由Be

qq_43456605的博客 1233

Spring AOP(二) Spring AOP 完整指南

本文详细介绍了Spring AOP的核心概念和使用方法。主要内容包括:1)@Around切入点表达式大全,列举了10种常用表达式及其语法;2)execution表达式详解,提供10个典型示例和通配符说明;3)组合表达式的逻辑运算符使用;4)五种通知类型的对比表格,包含执行时机和控制能力;5)各通知类型的代码实现示例;6)正常和异常情况下的执行顺序流程图;7)一个完整的日志切面实战案例。文章全面覆盖了Spring AOP的核心知识点,为开发者提供了实用的参考指南。

A-Itfuture的博客 511

Spring (二)—— Spring AOP

文章目录AOP概念AOP相关术语AOP的实现通过配置实现通过注解实现 AOP概念 AOP是面向切面,即扩展功能但是不修改源代码,AOP采取横向抽取机制,一般用于 性能监控、事务管理、安全检查、缓存; 这里先介绍一下纵向抽取机制: 我们一般添加功能是这样做的: public class User { public void add() { //添加用户的功能 ...

中都 574

二、Spring5框架之AOP

AOP AOP(概念) (1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得 业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 (2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能 (3)使用例子说明 AOP AOP 底层使用动态代理 1、什么是 AOP (1)有两种情况动态代理 第一种 有接口情况,使用 JDK 动态代理 1、创建接口实现类代理对象,增强类的方法 第二种 没有接口情况,使用 CGLIB 动态代理 1、创建子类的代理对

qq_41231318的博客 291

SSM之Spring AOP【篇二】

JDK动态代理回顾 (1)动态代理,必须要有一个接口 (2)动态代理的三个参数 代理类,与被代理类 地位是一样的 所以,有相同的接口,相同的类加载器 (3)invoke方法 参1 一般不用,代理对象 参2 表示要增强哪个方法 AOP的术语 1、 目标类target:就是我们需要增强的那个类 LaoZong.class 2、 代理类proxy:就是自定义的代理的对象 $Proxy0.class 3、 连接点joinPoint:程序执行的某个特定位置,Spring仅支持方法的连接点 eat(),sleep(

syy567的博客 168

Spring Aop(二)——基于Aspectj注解的Aop简单实现

2 基于Aspectj注解的Spring Aop简单实现Spring Aop是基于Aop框架Aspectj实现的,它不是完完全全的对Aspectj框架进行扩展和改造,而是利用Aspectj里面的一些功能来实现自己的Aop框架,其中就包括对Aspectj提供的注解的解析。之前已经提过Spring Aop和Aspectj实现的Aop之间的差别,这里就不再赘述。本文主要描述的是如何利用Aspectj提供

Elim的博客 3636

二刷能变强系列-Spring AOP

一.问题引入 当我们需要升级业务修改逻辑代码时,我们要保证升级后的业务代码需要兼容以前的处理逻辑,也就是说再保留原有的功能逻辑的基础上,进行新的业务功能开发,这个时候就需要我们去修改当前的功能方法源码,增加新的逻辑代码,然后重新运行项目,这个时候就会出现: (1)假如我们有当前功能方法的源码,就需要阅读当前方法的源码,然后在增加自己的新的逻辑代码,并且修改后,需要将新的类文件替换旧的类文件,本身阅读代码效率较低。 (2)假如我们没有源码,那就无法直接修改源码,哪还怎么升级? 二.解决方法 方案一: 我们有一

WANG__Q的博客 213
上一篇: Spring AOP 总结一
下一篇: Spring AOP 总结三
机器挖掘工
博客等级 码龄11年 892粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

机器挖掘工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值