Spring AOP 源码解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 基于Spring Boot 的AOP启动的源码解析,分析在Spring Boot 容器启动时,AOP的过程

基本概念

AOP 是面向切面|面向方面编程的简称,Aspect-Oriented Programming。 Aspect 是一种模块化机制,是用来描述分散在对象,类,函数中的横切关注点。从关注点分离出横切关注点是面向切面的程序设计的核心概念。分离关注点使解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不在含有针对特定领域问题的代码调用,业务逻辑和特定领域的问题的关系通过切面来封装,维护,这样原本分散在整个程序中的变动就可以很好的管理起来了。

基础: 待增强对象或者目标对象

切面: 包含对基础的增强应用

配置: 可以看成一种编织,通过在AOP体系中提供这个配置环境,将基础和切面结合起来,从而完成切面对目标对象的编织实现

Advice(通知): 定义在连接点做什么,为切面增强提供织入接口。在Spring AOP 中,它主要描述Spring AOP 围绕方法调用而注入的切面行为。

Pointcut(切点):决定Advice通知应该作用于哪个连接点,也就是说通过Pointcut来定义需要增强的方法集合。

Advisor(通知器):完成对目标方法的切面增强设计(advice)和关注点的设计以后,需要一个对象把它们结合起来,完成这个作用的就是Advisor(通知器)。通过Advisor ,可以定义应该使用那个通知并在哪个关注点使用它。

源码分析

### 启动过程
在Sprint Boot 启动类上加入 注解 @EnableAspectJAutoProxy(proxyTargetClass = true) ,注解源码为:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;

    boolean exposeProxy() default false;
}

​ 该注解使用 @Import 注解引入 AspectJAutoProxyRegistrar , 跟踪 AspectJAutoProxyRegistrar 类:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * Register, escalate, and configure the AspectJ auto proxy creator based on the value
     * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
     * {@code @Configuration} class.
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata , 
                                                                        BeanDefinitionRegistry registry) {
        /* 
        往容器中注入AnnotationAwareAspectJAutoProxyCreator类,bean名称为 org.springframework.aop.config.internalAutoProxyCreator
        */
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
        /*
            读取主配置类的 EnableAspectJAutoProxy的注解的属性
        */
        AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata,     
                                            EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }
}

通过源码发现,AspectJAutoProxyRegistrar 类 实现了ImportBeanDefinitionRegistrar 接口,在容器启动的时候会调用所有实现ImportBeanDefinitionRegistrar的 bean 的registerBeanDefinitions 方法。在方法内部:
1.调用 org.springframework.aop.config.AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary(org.springframework.beans.factory.support.BeanDefinitionRegistry)

a. 在`registerAspectJAnnotationAutoProxyCreatorIfNecessary` 方法内部:

  public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, (Object)null);
}
  
  1. 最终调用 org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired 方法, 参数cls 为 AnnotationAwareAspectJAutoProxyCreator.class
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
  Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
  if (registry.containsBeanDefinition(
    "org.springframework.aop.config.internalAutoProxyCreator")) {
      BeanDefinition apcDefinition = registry.getBeanDefinition(
        "org.springframework.aop.config.internalAutoProxyCreator");
      if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
          int currentPriority = findPriorityForClass(
            apcDefinition.getBeanClassName());
          int requiredPriority = findPriorityForClass(cls);
          if (currentPriority < requiredPriority) {
              apcDefinition.setBeanClassName(cls.getName());
          }
      }

      return null;
  } else {
      RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
      beanDefinition.setSource(source);
      beanDefinition.getPropertyValues().add("order", -2147483648);
      beanDefinition.setRole(2);
      registry.registerBeanDefinition(
        "org.springframework.aop.config.internalAutoProxyCreator",   
        beanDefinition);
      return beanDefinition;
  }
}

在方法内部, 首先检查容器中是否包含名称为 org.springframework.aop.config.internalAutoProxyCreator 的bean ,容器第一次启动总不包含该bean,进入else 逻辑,创建一个 AnnotationAwareAspectJAutoProxyCreator.class的bean定义,并且注册bean的名称为AnnotationAwareAspectJAutoProxyCreator.class

2.调用org.springframework.context.annotation.AnnotationConfigUtils#attributesFor(org.springframework.core.type.AnnotatedTypeMetadata, java.lang.Class<?>) 该类主要完成 读取主配置类的 EnableAspectJAutoProxy的注解的属性。 主要检查 proxyTargetClassexposeProxy 属性的值

AnnotationAwareAspectJAutoProxyCreator

在容器启动的过程中, AOP 向容器中注入了一个 AnnotationAwareAspectJAutoProxyCreator 的 bean , 我们来分析一下这个bean 。
类的继承体系 :
image.png
通过 类的继承体系,我们发现 AnnotationAwareAspectJAutoProxyCreator 实现了 BeanFactoryAware ,BeanClassLoaderAware, SmartInstantiationAwareBeanPostProcessor,InstantiationAwareBeanPostProcessor , BeanPostProcessor , BeanClassLoaderAware 等接口 来介入容器启动过程容Bean的生命周期。
类的接口实现:
AOP类继承图.jpg
AnnotationAwareAspectJAutoProxyCreator的接口实现中:

BeanFactoryAware接口
定义了setBeanFactory 接口, 在容器启动的时候调用org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#setBeanFactory

@Override
public void setBeanFactory(BeanFactory beanFactory) {
  // 设置容器
  super.setBeanFactory(beanFactory);
  if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
  throw new IllegalArgumentException(
  "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
  }
  initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}

protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 创建增强器探索工具
  this.advisorRetrievalHelper = new     BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}

其中initBeanFactory 最终调用org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#initBeanFactory

@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  // 调用父类的initBeanFactory方法
  super.initBeanFactory(beanFactory);
  if (this.aspectJAdvisorFactory == null) {
    // 创建Aspect增强器工厂
    this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
  }
  // 创建一个增强器的构建器
  this.aspectJAdvisorsBuilder =
    new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}

InstantiationAwareBeanPostProcessor接口
我们知道在spring 容器创建任意一个bean的过程中。在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean的方法中:

@Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        // ... 省略代码

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            //... 省略代码
    }

在调用真正创建bean的方法doCreateBean 之前, 先调用了 resolveBeforeInstantiation方法。 我们跟踪org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation 方法:

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
  Object bean = null;
  if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
    // Make sure bean class is actually resolved at this point.
    // 当容器中存在InstantiationAwareBeanPostProcessors 时,调用InstantiationAwareBeanPostProcessors 的 postProcessBeforeInstantiation 方法和 postProcessAfterInitialization 方法
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      Class<?> targetType = determineTargetType(beanName, mbd);
      if (targetType != null) {
        bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
        if (bean != null) {
          bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        }
      }
    }
    mbd.beforeInstantiationResolved = (bean != null);
  }
  return bean;
}

当容器中存在InstantiationAwareBeanPostProcessors的bean时
1.先调用applyBeanPostProcessorsBeforeInstantiation方法,
2.然后在调用applyBeanPostProcessorsAfterInitialization 方法
跟踪 applyBeanPostProcessorsBeforeInstantiation 方法

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    // 获取容器中所有BeanPostProcessor, 若BeanPostProcessor 是InstantiationAwareBeanPostProcessor ,则调用其 postProcessBeforeInstantiation 方法
  for (BeanPostProcessor bp : getBeanPostProcessors()) {
    if (bp instanceof InstantiationAwareBeanPostProcessor) {
      InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
      Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
      if (result != null) {
        return result;
      }
    }
  }
  return null;
}

applyBeanPostProcessorsBeforeInstantiation 方法内部,首先获取容器中所有BeanPostProcessor

BeanPostProcessorInstantiationAwareBeanPostProcessor

则调用其 postProcessBeforeInstantiation 方法 。

​ 然后我们在容器启动的时候,在容器中注册了AnnotationAwareAspectJAutoProxyCreator 并且这个bean 实现的InstantiationAwareBeanPostProcessor接口,所以在容器创建bean的时候,会触发AnnotationAwareAspectJAutoProxyCreatorapplyBeanPostProcessorsBeforeInstantiation方法。

这个是Spring AOP 的真正入口。

接下来我们详细分析:

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiationAnnotationAwareAspectJAutoProxyCreator 继承了 AbstractAutoProxyCreator

postProcessBeforeInstantiation

调用链:
postProcessBeforeInstantiation调用链图.jpg

详细分析:
在postProcessBeforeInstantiation 中查找所有的增强器org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation的源码如下,在容器创建任何一个bean的时候触发:

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
  //1.先获取 bean的key
  Object cacheKey = getCacheKey(beanClass, beanName);
    //2. 判断bean是否已经处理过,处理过的bean被放入targetSourcedBeans 集合中。
  if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
    //3.判断是否已经包含bean的增强器
    if (this.advisedBeans.containsKey(cacheKey)) {
      return null;
    }
    //4.判断bean类型 和 是否应该跳过
    if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return null;
    }
  }

  // Create proxy here if we have a custom TargetSource.
  // Suppresses unnecessary default instantiation of the target bean:
  // The TargetSource will handle target instances in a custom fashion.
  TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
  if (targetSource != null) {
    if (StringUtils.hasLength(beanName)) {
      this.targetSourcedBeans.add(beanName);
    }
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, 
                                                                 beanName, targetSource);
    // 创建代理bean
    Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
    this.proxyTypes.put(cacheKey, proxy.getClass());
    return proxy;
  }

  return null;
}

1.先获取 bean的key
2.判断bean是否已经处理过,处理过的bean被放入targetSourcedBeans 集合中。
3.判断是否已经包含bean的增强器
4.判断是否是需要增强的bean

a.判断bean的类型是否为基础类:Advice,Pointcut,Advisor,AopInfrastructureBean进入isInfrastructureClass源码:
protected boolean isInfrastructureClass(Class<?> beanClass) {
  boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
    Pointcut.class.isAssignableFrom(beanClass) ||
      Advisor.class.isAssignableFrom(beanClass) ||
        AopInfrastructureBean.class.isAssignableFrom(beanClass);
  if (retVal && logger.isTraceEnabled()) {
    logger.trace("");
  }
  return retVal;
}

b.判断是否跳过处理,进入shouldSkip方法源码

 @Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {

// 查找容器中所有的候选的增强器列表
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 若列表中包含当前bean的增强器,返回true
for (Advisor advisor : candidateAdvisors) {
  if (advisor instanceof AspectJPointcutAdvisor &&
      ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
    return true;
  }
}
return super.shouldSkip(beanClass, beanName);
}

跟踪findCandidateAdvisors 方法内部:

@Override
protected List<Advisor> findCandidateAdvisors() {
  // Add all the Spring advisors found according to superclass rules.
  // 容器中所有实现Advisor接口的bean组件,熟悉 Spring 事物的都知道,Advisor接口是为Spring事务服务的
  List<Advisor> advisors = super.findCandidateAdvisors();
  // Build Advisors for all AspectJ aspects in the bean factory.
  // 查找容器是标注@Aspect 组件的bean ,并解析bean的标注 @Before, @After, @AfterReturning, @AfterThrowing 的方法,即查找增强器。并加入缓存中。
  if (this.aspectJAdvisorsBuilder != null) {
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  }
  return advisors;
}

5.后续第一次执行不到

postProcessAfterInitialization

调用链:
postProcessAfterInitialization调用链.jpg
详细过程:
跟踪org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization源码:

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
  if (bean != null) {
    Object cacheKey = getCacheKey(bean.getClass(), beanName);
    if (this.earlyProxyReferences.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;
  }
  // 判断是否生成代理对象
  if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
  }
    // 获取通知和增强器
  // Create proxy if we have advice.
  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;
}

跟踪getAdvicesAndAdvisorsForBean()方法最终调用:org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors:

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
 // 找到候选的增强器
  List<Advisor> candidateAdvisors = findCandidateAdvisors();
  // 筛选可用的增强器
  List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  // 扩展
  extendAdvisors(eligibleAdvisors);
  if (!eligibleAdvisors.isEmpty()) {
    // 排序
    eligibleAdvisors = sortAdvisors(eligibleAdvisors);
  }
  return eligibleAdvisors;
}

跟踪: findCandidateAdvisors():

@Override
protected List<Advisor> findCandidateAdvisors() {
  // Add all the Spring advisors found according to superclass rules.
  // 查找所有 实现Advisor的接口的增强器
  List<Advisor> advisors = super.findCandidateAdvisors();
  // Build Advisors for all AspectJ aspects in the bean factory.
  if (this.aspectJAdvisorsBuilder != null) {
    // 查找所有Aspect ,查找容器是标注@Aspect 组件的bean ,并解析bean的标注 @Before, @After, @AfterReturning, @AfterThrowing 的方法,即查找增强器。并加入缓存中。
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  }
  return advisors;
}

跟踪:findAdvisorsThatCanApply 并最终调用:org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
  if (candidateAdvisors.isEmpty()) {
    return candidateAdvisors;
  }
  List<Advisor> eligibleAdvisors = new ArrayList<>();
  for (Advisor candidate : candidateAdvisors) {
    if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
      eligibleAdvisors.add(candidate);
    }
  }
  boolean hasIntroductions = !eligibleAdvisors.isEmpty();
  for (Advisor candidate : candidateAdvisors) {
    if (candidate instanceof IntroductionAdvisor) {
      // already processed
      continue;
    }
    if (canApply(candidate, clazz, hasIntroductions)) {
      eligibleAdvisors.add(candidate);
    }
  }
  return eligibleAdvisors;
}

进入 canApply方法: 最终调用:org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)方法:

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
  Assert.notNull(pc, "Pointcut must not be null");
  if (!pc.getClassFilter().matches(targetClass)) {
    return false;
  }

  MethodMatcher methodMatcher = pc.getMethodMatcher();
  if (methodMatcher == MethodMatcher.TRUE) {
    // No need to iterate the methods if we're matching any method anyway...
    return true;
  }
    // 创建方法匹配器
  IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
  if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
    introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
  }

  Set<Class<?>> classes = new LinkedHashSet<>();
  if (!Proxy.isProxyClass(targetClass)) {
    classes.add(ClassUtils.getUserClass(targetClass));
  }
  classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

  for (Class<?> clazz : classes) {
    Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
    for (Method method : methods) {
      if (introductionAwareMethodMatcher != null ?
          introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
          // 匹配切面的方法
          methodMatcher.matches(method, targetClass)) {
        return true;
      }
    }
  }

  return false;
}

getAdvicesAndAdvisorsForBean 方法逻辑分析结束。

跟踪createProxy 方法:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy

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

  if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
    AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
  }
    // 创建代理工厂
  ProxyFactory proxyFactory = new ProxyFactory();
  proxyFactory.copyFrom(this);
    // 设置使用JDK代理还是使用CGLIB代理
  if (!proxyFactory.isProxyTargetClass()) {
    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);
  }
    // 创建代理对象, 代理对象持有 增强器。
  return proxyFactory.getProxy(getProxyClassLoader());
}

这样 postProcessAfterInitialization 的逻辑就分析。

总结

在分析了Spring AOP的启动过程,总结一下总体过程:

1.setBeanFacotry 接口,在容器启动的时候,创建了 BeanFactoryAdvisorRetrievalHelperAdapter 增强器探索更具和BeanFactoryAspectJAdvisorsBuilderAdapter 增强器的构建器

2.postProcessBeforeInstantiation 接口: 查找所有的切面和Advisor,并将切面的通知解析,构建成初步的增强器,加入到缓存中来。

3.postProcessAfterInitialization 接口,从缓存取出所有的将所有的增强器,创建代理工厂,并织入增强器,创建代理对象

调用过程:

待更新...

目录
相关文章
|
13天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
15天前
|
搜索推荐 Java Spring
Spring Filter深度解析
【10月更文挑战第21天】Spring Filter 是 Spring 框架中非常重要的一部分,它为请求处理提供了灵活的控制和扩展机制。通过合理配置和使用 Filter,可以实现各种个性化的功能,提升应用的安全性、可靠性和性能。还可以结合具体的代码示例和实际应用案例,进一步深入探讨 Spring Filter 的具体应用和优化技巧,使对它的理解更加全面和深入。
|
2天前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
22 9
|
10天前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
28 3
|
27天前
|
存储
让星星⭐月亮告诉你,HashMap的put方法源码解析及其中两种会触发扩容的场景(足够详尽,有问题欢迎指正~)
`HashMap`的`put`方法通过调用`putVal`实现,主要涉及两个场景下的扩容操作:1. 初始化时,链表数组的初始容量设为16,阈值设为12;2. 当存储的元素个数超过阈值时,链表数组的容量和阈值均翻倍。`putVal`方法处理键值对的插入,包括链表和红黑树的转换,确保高效的数据存取。
51 5
|
28天前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
|
28天前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
24天前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
61 0
|
6月前
|
Java 关系型数据库 数据库连接
Spring源码解析--深入Spring事务原理
本文将带领大家领略Spring事务的风采,Spring事务是我们在日常开发中经常会遇到的,也是各种大小面试中的高频题,希望通过本文,能让大家对Spring事务有个深入的了解,无论开发还是面试,都不会让Spring事务成为拦路虎。
87 1
|
1月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
120 9

推荐镜像

更多
下一篇
无影云桌面