文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

大厂高频面试题Spring Bean生命周期详解

2024-12-02 14:41

关注

Spring作为当前Java最流行、最强大的轻量级框架。Spring Bean的生命周期也是面试高频题,了解Spring Bean周期也能更好地帮助我们解决日常开发中的问题。程序员应该都知道Spring的基础容器是ApplicationContext。应很多粉丝的强烈建议,本文我来分析分析 ApplicationContext中Bean的生命周期。ApplicationContext是顶层容器接口BeanFactory的实现类,因此,我们了解了ApplicationContext的生命周期逻辑,也基本上了解了其他类型容器的生命周期逻辑。

一、Spring生命周期流程图

下面先来看一张Spring Bean完整的生命周期流程图,下图描述的是从Spring容器初始化Bean开始直到Spring容器销毁Bean,所经历的关键节点。

从上图可以看出,Spring Bean的生命周期管理的基本思路是:在Bean出现之前,先准备操作Bean的BeanFactory,然后操作完Bean,所有的Bean也还会交给BeanFactory进行管理。在所有Bean操作准备BeanPostProcessor作为回调。在Bean的完整生命周期管理过程中,经历了以下主要几个步骤:

1.1 Bean创建前的准备阶段

步骤1:Bean容器在配置文件中找到Spring Bean的定义以及相关的配置,如init-method和destroy-method指定的方法。步骤2:实例化回调相关的后置处理器如BeanFactoryPostProcessor、BeanPostProcessor、InstantiationAwareBeanPostProcessor等

1.2 创建Bean的实例

步骤3:Srping 容器使用Java反射API创建Bean的实例。步骤4:扫描Bean声明的属性并解析。

1.3 开始依赖注入

步骤5:开始依赖注入,解析所有需要赋值的属性并赋值。步骤6:如果Bean类实现BeanNameAware接口,则将通过传递Bean的名称来调用setBeanName()方法。步骤7:如果Bean类实现BeanFactoryAware接口,则将通过传递BeanFactory对象的实例来调用setBeanFactory()方法。步骤8:如果有任何与BeanFactory关联的BeanPostProcessors对象已加载Bean,则将在设置Bean属性之前调用postProcessBeforeInitialization()方法。步骤9:如果Bean类实现了InitializingBean接口,则在设置了配置文件中定义的所有Bean属性后,将调用afterPropertiesSet()方法。

1.4 缓存到Spring容器

步骤10:如果配置文件中的Bean定义包含init-method属性,则该属性的值将解析为Bean类中的方法名称,并将调用该方法。步骤11:如果为Bean Factory对象附加了任何Bean 后置处理器,则将调用postProcessAfterInitialization()方法。

1.5 销毁Bean的实例

步骤12:如果Bean类实现DisposableBean接口,则当Application不再需要Bean引用时,将调用destroy()方法。步骤13:如果配置文件中的Bean定义包含destroy-method属性,那么将调用Bean类中的相应方法定义。

二、代码实战演示

下面我们用一个简单的Bean来演示并观察一下Spring Bean完整的生命周期。

2.1 准备Author类

首先是一个简单的Bean,调用Bean自身的方法和Bean级生命周期接口方法,为了方便演示,它实现了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这4个接口,同时添加2个init-method和destory-method方法,对应配置文件中的init-method和destroy-method。具体代码如下:

  1. package com.tom.lifecycle; 
  2.  
  3. import lombok.Data; 
  4. import lombok.extern.slf4j.Slf4j; 
  5. import org.springframework.beans.BeansException; 
  6. import org.springframework.beans.factory.*; 
  7.  
  8. @Slf4j 
  9. @Data 
  10. public class Author implements BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean { 
  11.     private String name
  12.     private String address; 
  13.     private int age; 
  14.  
  15.     private BeanFactory beanFactory; 
  16.  
  17.     private String beanName; 
  18.  
  19.     public Author() { 
  20.         log.info("【构造器】调用Tom类的构造器实例化"); 
  21.     } 
  22.  
  23.     public void setName(String name) { 
  24.         log.info("【注入属性】name"); 
  25.         this.name = name
  26.     } 
  27.  
  28.     public void setAddress(String address) { 
  29.         log.info("【注入属性】address"); 
  30.         this.address = address; 
  31.     } 
  32.  
  33.     public void setAge(int age) { 
  34.         log.info("【注入属性】age"); 
  35.         this.age = age; 
  36.     } 
  37.  
  38.     // 实现BeanFactoryAware接口的方法 
  39.     public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 
  40.         log.info("【BeanFactoryAware接口】调用setBeanFactory方法"); 
  41.         this.beanFactory = beanFactory; 
  42.     } 
  43.  
  44.     // 实现BeanNameAware接口的方法 
  45.     public void setBeanName(String beanName) { 
  46.         log.info("【BeanNameAware接口】调用setBeanName方法"); 
  47.         this.beanName = beanName; 
  48.     } 
  49.  
  50.     // 实现DiposibleBean接口的方法 
  51.     public void destroy() throws Exception { 
  52.         log.info("【DiposibleBean接口】调用destroy方法"); 
  53.     } 
  54.  
  55.     // 实现InitializingBean接口的方法 
  56.     public void afterPropertiesSet() throws Exception { 
  57.         log.info("【InitializingBean接口】调用afterPropertiesSet方法"); 
  58.     } 
  59.  
  60.     // 通过的init-method属性指定的初始化方法 
  61.     public void beanInit() { 
  62.         log.info("【init-method】调用的init-method属性指定的初始化方法"); 
  63.     } 
  64.  
  65.     // 通过的destroy-method属性指定的初始化方法 
  66.     public void beanDestory() { 
  67.         log.info("【destroy-method】调用的destroy-method属性指定的初始化方法"); 
  68.     } 

在配置Spring配置文件中加入如下内容:

  1. "author" class="com.tom.lifecycle.Author" 
  2.       init-method="beanInit" 
  3.       destroy-method="beanDestory" 
  4.       scope="singleton" 
  5.       p:name="Tom" p:address="湖南长沙" p:age="18"/> 

2.2 演示BeanFactoryPostProcessor的执行

创建GPBeanFactoryPostProcessor类,并实现BeanFactoryPostProcessor接口,具体代码如下:

  1. package com.tom.lifecycle; 
  2.  
  3. import lombok.extern.slf4j.Slf4j; 
  4. import org.springframework.beans.BeansException; 
  5. import org.springframework.beans.factory.config.BeanDefinition; 
  6. import org.springframework.beans.factory.config.BeanFactoryPostProcessor; 
  7. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 
  8.  
  9. @Slf4j 
  10. public class GPBeanFactoryPostProcessor implements BeanFactoryPostProcessor{ 
  11.  
  12.     public GPBeanFactoryPostProcessor() { 
  13.         super(); 
  14.         log.info("调用BeanFactoryPostProcessor实现类构造器!!"); 
  15.     } 
  16.  
  17.     public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { 
  18.         log.info("BeanFactoryPostProcessor调用postProcessBeanFactory方法"); 
  19.         BeanDefinition bd = configurableListableBeanFactory.getBeanDefinition("author"); 
  20.         bd.getPropertyValues().addPropertyValue("age""16"); 
  21.     } 

在配置Spring配置文件中加入如下内容:

  1. "beanFactoryPostProcessor" class="com.tom.lifecycle.GPBeanFactoryPostProcessor" /> 

编写测试类BeanLifeCycleTest,具体代码如下:

  1. package com.tom.lifecycle; 
  2.  
  3. import lombok.extern.slf4j.Slf4j; 
  4. import org.springframework.context.ApplicationContext; 
  5. import org.springframework.context.support.ClassPathXmlApplicationContext; 
  6.  
  7. @Slf4j 
  8. public class BeanLifeCycleTest { 
  9.  
  10.     public static void main(String[] args) { 
  11.  
  12.         log.info("====== 开始初始化Spring容器 ========"); 
  13.  
  14.         ApplicationContext factory = new ClassPathXmlApplicationContext("application-beans.xml"); 
  15.  
  16.         log.info("====== 初始化Spring容器成功 ========"); 
  17.  
  18.         //获取Author实例 
  19.         Author author = factory.getBean("author", Author.class); 
  20.  
  21.         log.info(author.toString()); 
  22.  
  23.         log.info("====== 开始销毁Spring容器 ========"); 
  24.  
  25.         ((ClassPathXmlApplicationContext) factory).registerShutdownHook(); 
  26.     } 
  27.  

运行结果

运行结果如下:

  1. 15:49:12.477 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - 调用BeanPostProcessor实现类构造器!! 
  2. 15:49:12.494 [main] INFO com.tom.lifecycle.Author - 【构造器】调用Tom类的构造器实例化 
  3. 15:49:12.527 [main] INFO com.tom.lifecycle.Author - 【注入属性】address 
  4. 15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【注入属性】age 
  5. 15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【注入属性】name 
  6. 15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【BeanNameAware接口】调用setBeanName方法 
  7. 15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【BeanFactoryAware接口】调用setBeanFactory方法 
  8. 15:49:12.528 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改 
  9. 15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【InitializingBean接口】调用afterPropertiesSet方法 
  10. 15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【init-method】调用的init-method属性指定的初始化方法 
  11. 15:49:12.528 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改 
  12. 15:49:12.531 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - ====== 初始化Spring容器成功 ======== 
  13. 15:49:12.531 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - Author(name=Tom, address=湖南长沙, age=18, beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@26653222: defining beans [beanPostProcessor,author]; root of factory hierarchy, beanName=author) 
  14. 15:49:12.531 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - ====== 开始销毁Spring容器 ======== 
  15. 15:49:12.532 [Thread-0] INFO com.tom.lifecycle.Author - 【DiposibleBean接口】调用destroy方法 
  16. 15:49:12.533 [Thread-0] INFO com.tom.lifecycle.Author - 【destroy-method】调用的destroy-method属性指定的初始化方法 

我们看到,整个执行和我们一开始绘制的流程图一致。但是为什么我们要实现BeanFactoryPostProcessor接口呢?我们进入到BeanFactoryPostProcessor的源码如下:

  1. package org.springframework.beans.factory.config; 
  2.  
  3. import org.springframework.beans.BeansException; 
  4.  
  5. public interface BeanFactoryPostProcessor { 
  6.     void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException; 

BeanFactoryPostProcessor接口只有一个postProcessBeanFactory()方法,BeanFactoryPostProcessor:在BeanFactory标准初始化之后可以进行修改。将加载所有Bean定义,但是还没有实例化Bean。这个方法允许重新覆盖或者添加属性甚至快速的初始化bean。初次看到可能不知道postProcessBeanFactory()到底是干嘛的。要想透彻理解这个方法的作用,下面来进入到BeanFactoryPostProcessor的源码,理解一下postProcessBeanFactory()的参数,我们可以利用这些参数做一些操作。

通过参数来看,只有一个ConfigurableListableBeanFactory类,这个类的可以提供分析、修改Bean定义和预先实例化单例的功能。我们再进入到ConfigurableListableBeanFactory的源码中:

  1. public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory { 
  2.  
  3.         //忽略被给定注入依赖类型 ,例如String 
  4.     void ignoreDependencyType(Class var1); 
  5.  
  6.         //略被给定注入依赖接口 。这个通常被使用由ApplicationContext去注册依赖,可以以多种方式实现。例如BeanFactory通过BeanFactoryAware,ApplicationContext 通过ApplicationContextAware。默认情况下,仅BeanFactoryAware接口是被忽略,需要忽略其他接口,调用此方法 
  7.     void ignoreDependencyInterface(Class var1); 
  8.  
  9.         //注册一个特定类型依赖伴随着相应的Autowired值。这个是准备被用于应该可以Autowire而不是在这个工厂被定义的Bean的工厂/上下文引用。例如 将ApplicationContext类型的依赖项解析为Bean所在的ApplicationContext实例。注意~在普通的BeanFactory中没有注册这样的默认类型,甚至连BeanFactory接口本身都没有 
  10.     void registerResolvableDependency(Class var1, Object var2); 
  11.  
  12.         //确认这个被指定的Bean是否是一个Autowire候选,将被注入到其他声明匹配类型的依赖的Bean中 
  13.     boolean isAutowireCandidate(String var1, DependencyDescriptor var2) throws NoSuchBeanDefinitionException; 
  14.  
  15.         //根据指定的beanName返回被注册的Bean定义,允许访问其属性值和构造函数参数值(可以在BeanFactory后期处理期间被修改)。这个被返回的BeanDefinition对象不应该是副本而是原始在工厂被注册的。这意味着如果需要它可以被转换为更具体的实现类型。注意这个方法只能获得本地工厂BeanDefinition 
  16.     BeanDefinition getBeanDefinition(String var1) throws NoSuchBeanDefinitionException; 
  17.  
  18.         //冻结全部Bean定义,给被注册的Bean定义发信号告诉它们今后不再被修改和进一步后续处理。它允许Factory去积极缓存Bean定义元数据 
  19.     void freezeConfiguration(); 
  20.  
  21.         //返回该工厂的BeanDefinnition是否被冻结 
  22.     boolean isConfigurationFrozen(); 
  23.  
  24.         //确保所有非懒加载的单例Bean被实例化,包括FactoryBean 
  25.     void preInstantiateSingletons() throws BeansException; 

通过以上演示和分析,我们应该大概能够了解ConfigurableListableBeanFactory的作用,基本就都是对于Bean定义的操作。至此我们还没有看到BeanPostProcessor 和InstantiationAwareBeanPostProcessor的调用。下面我们把BeanPostProcessor 和InstantiationAwareBeanPostProcessor的实现补充上来,再看完整的执行流程

2.3 实现BeanPostProcessor

创建GPBeanPostProcessor类,并实现BeanPostProcessor 接口,具体代码如下:

  1. package com.tom.lifecycle; 
  2.  
  3. import lombok.extern.slf4j.Slf4j; 
  4. import org.springframework.beans.BeansException; 
  5. import org.springframework.beans.factory.config.BeanPostProcessor; 
  6.  
  7. @Slf4j 
  8. public class GPBeanPostProcessor implements BeanPostProcessor { 
  9.  
  10.     public GPBeanPostProcessor(){ 
  11.         log.info("调用BeanPostProcessor实现类构造器!!"); 
  12.     } 
  13.     public Object postProcessBeforeInitialization(Object o, String s) throws BeansException { 
  14.         log.info("BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改"); 
  15.         return o; 
  16.     } 
  17.  
  18.     public Object postProcessAfterInitialization(Object o, String s) throws BeansException { 
  19.         log.info("BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改"); 
  20.         return o; 
  21.     } 

ApplicationContext 可以在BeanDefinition中自动检测到实现了BeanPostProcessor的Bean,并且把这些Bean应用于随后的Bean创建。普通的BeanFactory允许对后处理器进行程序化注册,通过工厂应用于所有Bean创建。BeanPostProcessor接口中主要有两个方法:| 方法名 | 解释 | | -------- | -------- | | postProcessBeforeInitialization | 在Bean实例化回调(例如InitializingBean的afterPropertiesSet 或者一个定制的init-method)之前应用此BeanPostProcessor | | postProcessAfterInitialization | 在bean实例化回调(例如InitializingBean的afterPropertiesSet 或者一个定制的init-method)之后应用此BeanPostProcessor |

2.4 实现InstantiationAwareBeanPostProcessor

创建GPInstantiationAwareBeanPostProcessor类,并实现InstantiationAwareBeanPostProcessorAdapter接口,具体代码如下:

  1. package com.tom.lifecycle; 
  2.  
  3. import lombok.extern.slf4j.Slf4j; 
  4. import org.springframework.beans.BeansException; 
  5. import org.springframework.beans.PropertyValues; 
  6. import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; 
  7.  
  8. import java.beans.PropertyDescriptor; 
  9.  
  10. @Slf4j 
  11. public class GPInstantiationAwareBeanPostProcessor  extends InstantiationAwareBeanPostProcessorAdapter { 
  12.  
  13.     public GPInstantiationAwareBeanPostProcessor() { 
  14.         super(); 
  15.         log.info("调用InstantiationAwareBeanPostProcessorAdapter实现类构造器!!"); 
  16.     } 
  17.  
  18.     // 接口方法、实例化Bean之前调用 
  19.     @Override 
  20.     public Object postProcessBeforeInstantiation(Class beanClass,String beanName) throws BeansException { 
  21.         log.info("InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法"); 
  22.         return null
  23.     } 
  24.  
  25.     // 接口方法、实例化Bean之后调用 
  26.     @Override 
  27.     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 
  28.         log.info("InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法"); 
  29.         return bean; 
  30.     } 
  31.  
  32.     // 接口方法、设置某个属性时调用 
  33.     @Override 
  34.     public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { 
  35.         log.info("InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法"); 
  36.         return pvs; 
  37.     } 

实现InstantiationAwareBeanPostProcessorAdapter的Bean之后,可以在实例化成功之后,做一些校验或者补充些内容或者把Bean包装代理注入。实现InstantiationAwareBeanPostProcessorAdapter的Bean之后,不会影响容器正常处理每一个实例化的Bean,其子类仅仅只是根据需要覆盖父类的方法。

注意,只有在实际需要 InstantiationAwareBeanPostProcessor 功能时才推荐此基类。如果我们所需要的只是简单的BeanPostProcessor功能,那么直接实现更简单的接口即可。

下面详细介绍一下InstantiationAwareBeanPostProcessorAdapter接口中的所有方法:

2.5 修改配置文件

完整的配置文件内容如下:

  1. "1.0" encoding="UTF-8"?> 
  2.  
  3. "http://www.springframework.org/schema/beans" 
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" 
  5.     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 
  6.     xsi:schemaLocation=" 
  7.             http://www.springframework.org/schema/beans  
  8.             http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> 
  9.  
  10.         "beanPostProcessor" class="com.tom.lifecycle.GPBeanPostProcessor" /> 
  11.  
  12.         "beanFactoryPostProcessor" class="com.tom.lifecycle.GPBeanFactoryPostProcessor" /> 
  13.  
  14.         "instantiationAwareBeanPostProcessor" class="com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor" /> 
  15.  
  16.  
  17.         "author" class="com.tom.lifecycle.Author" 
  18.                 init-method="beanInit" 
  19.                 destroy-method="beanDestory" 
  20.                 scope="singleton" 
  21.                 p:name="Tom" p:address="湖南长沙" p:age="18"/> 
  22.  
  23.  

2.6 运行结果

最后,我们再次运行BeanLifeCycleTest测试类,看到如下运行结果:

  1. 15:56:20.030 [main] INFO com.tom.lifecycle.GPBeanFactoryPostProcessor - 调用BeanFactoryPostProcessor实现类构造器!! 
  2. 15:56:20.045 [main] INFO com.tom.lifecycle.GPBeanFactoryPostProcessor - BeanFactoryPostProcessor调用postProcessBeanFactory方法 
  3. 15:56:20.046 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - 调用BeanPostProcessor实现类构造器!! 
  4. 15:56:20.047 [main] INFO com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor - 调用InstantiationAwareBeanPostProcessorAdapter实现类构造器!! 
  5. 15:56:20.051 [main] INFO com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法 
  6. 15:56:20.052 [main] INFO com.tom.lifecycle.Author - 【构造器】调用Tom类的构造器实例化 
  7. 15:56:20.069 [main] INFO com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法 
  8. 15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【注入属性】address 
  9. 15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【注入属性】age 
  10. 15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【注入属性】name 
  11. 15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【BeanNameAware接口】调用setBeanName方法 
  12. 15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【BeanFactoryAware接口】调用setBeanFactory方法 
  13. 15:56:20.093 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改 
  14. 15:56:20.093 [main] INFO com.tom.lifecycle.Author - 【InitializingBean接口】调用afterPropertiesSet方法 
  15. 15:56:20.093 [main] INFO com.tom.lifecycle.Author - 【init-method】调用的init-method属性指定的初始化方法 
  16. 15:56:20.093 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改 
  17. 15:56:20.093 [main] INFO com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法 
  18. 15:56:20.097 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - ====== 初始化Spring容器成功 ======== 
  19. 15:56:20.098 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - Author(name=Tom, address=湖南长沙, age=16, beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@26653222: defining beans [beanPostProcessor,beanFactoryPostProcessor,instantiationAwareBeanPostProcessor,author]; root of factory hierarchy, beanName=author) 
  20. 15:56:20.098 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - ====== 开始销毁Spring容器 ======== 
  21. 15:56:20.099 [Thread-0] INFO com.tom.lifecycle.Author - 【DiposibleBean接口】调用destroy方法 
  22. 15:56:20.100 [Thread-0] INFO com.tom.lifecycle.Author - 【destroy-method】调用的destroy-method属性指定的初始化方法 

三、Spring Bean生命周期运行时序图

最后我们来看一下完整的执行时序图:

 

来源:Tom弹架构内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯