深入理解Spring容器体系结构「建议收藏」

深入理解Spring容器体系结构「建议收藏」前言在spring中,任何实现了BeanFactory接口的类都可以视为容器,它是IOC功能实现的核心,用于完成类实例从加载到销毁的整个生命周期的控制,这些被spring所管理的实例

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

前言

在 spring 中,任何实现了 BeanFactory 接口的类都可以视为容器,它是 IOC 功能实现的核心,用于完成类实例从加载到销毁的整个生命周期的控制,这些被 spring 所管理的实例统称为 bean。

根据抽象层级的不同,容器又分为 BeanFactory 的直接实现,与基于 BeanFactory 的扩展实现 ApplicationContext,后者在前者的基础继承了 ResourceLoaderEnvironmentCapable接口,因而具备从某类运行环境的资源中直接加载 bean 的能力。

image-20220620142154578

ApplicationContext 最常用的两个实现 ClassPathXmlApplicationContextAnnotationConfigApplicationContext ,前者用于从项目路径下根据 xml 文件加载 bean,而后者通过扫描类注解完成 bean 的加载。这两者 ApplicationContext 实际上就对应了我们所熟悉的两类配置方式,前者就是传统的 xml 配置,后者则是通过 @Component@Bean 等注解对 bean 进行配置。

本文将基于 spring 源码 5.2.x 分支,基于 BeanFactoryApplicationContext 两大接口,介绍 spring 的两类容器的结构体系。

一、BeanFactory 接口体系

总览 BeanFactory 体系,按照接口的抽象层次,大体可以分层四层:

  • 第一层:BeanFactory
  • 第二层:HierarchicalBeanFactoryListableBeanFactoryAutowireCapableBeanFactory
  • 第三层:ConfigurableBeanFactory,此外还有一个关联性较强SingletonBeanRegistry
  • 第四层:ConfigurableListableBeanFactory

image-20220620151809732

1、BeanFactory

BeanFactory 是整个容器体系最顶层的接口,它的内容如下:

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";
    // 获取bean相关的方法
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

    // 容器 bean 属性的一些判断
    boolean containsBean(String name);
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    // 获取 bean 在容器中的一些属性
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    String[] getAliases(String name);
}

我们可以直接从 BeanFactory 提供的方法看出,BeanFactory 定义了容器的一些基本能力:

  • 容器可以根据名称、类型、构造函数这三个要素,单独或两两组合的的获得一个 bean;
  • 容器获取的 bean 可以是单例多种多例的;
  • 容器中的 bean 可以拥有多个名称;

2、分层工厂,批量工厂,自动装配工厂

BeanFactory 存在两个子接口 HierarchicalBeanFactoryListableBeanFactory,它们进一步的扩展了容器的能力。

分层工厂 HierarchicalBeanFactory

HierarchicalBeanFactory 接口用于表示一个多集嵌套的 BeanFactory

public interface HierarchicalBeanFactory extends BeanFactory {
    // 获取父工厂
    BeanFactory getParentBeanFactory();
    // 当前工厂是否存在与名称对应的 bean
    boolean containsLocalBean(String name);
}

批量工厂 ListableBeanFactory

ListableBeanFactory 接口定义了容器根据类型、名称或类上的注解批量的获取 bean 或 bean 名称的能力:

public interface ListableBeanFactory extends BeanFactory {
    // 容器中是否存在 bean
    boolean containsBeanDefinition(String beanName);
    // 容器中定义了多少 bean
    int getBeanDefinitionCount();
    // 获取容器中所有定义了的 bean 名称
    String[] getBeanDefinitionNames();
    
    // 根据类型批量获取 bean
    String[] getBeanNamesForType(ResolvableType type);
    String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit);
    String[] getBeanNamesForType(@Nullable Class<?> type);
    String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
    <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
    <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException;
    
    // 根据类上的注解获取 bean
    String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
    Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
    <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) throws NoSuchBeanDefinitionException;
}

根据注释,当一个类同时实现了 HierarchicalBeanFactoryListableBeanFactory 接口时,ListableBeanFactory 中的方法是不会考虑到父工厂的,也就是说,spring 中的 ListableBeanFactory 接口表示的能力只针对当前实现它的类。

自动装配工厂 AutowireCapableBeanFactory

AutowireCapableBeanFactory 如同他的名称一样,用于为容器关联的 bean 提供自动装配功能:

public interface AutowireCapableBeanFactory extends BeanFactory {
    
    // 自动装配方式
	int AUTOWIRE_NO = 0; // 不自动装配
	int AUTOWIRE_BY_NAME = 1; // 根据bean名称自动装配
	int AUTOWIRE_BY_TYPE = 2; // 根据bean类型自动装配
	int AUTOWIRE_CONSTRUCTOR = 3; // 根据bean的构造方法自动装配
	int AUTOWIRE_AUTODETECT = 4; // 根据反射信息自动选择合适的方式自动装配,spring3 以后不再推荐该方式
	String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL";
    
    // bean的创建与装配相关的方法
	<T> T createBean(Class<T> beanClass) throws BeansException;
	void autowireBean(Object existingBean) throws BeansException;
	Object configureBean(Object existingBean, String beanName) throws BeansException;
    
    // bean 声明周期相关的方法
	Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
	Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
	void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck) throws BeansException;
	void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
	Object initializeBean(Object existingBean, String beanName) throws BeansException;
	Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException;
	Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException;
	void destroyBean(Object existingBean);
    
    // 获取 bean 依赖的相关方法
	<T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;
	Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException;
	Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
	Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
    
}

比较值得注意的是,通过 AutowireCapableBeanFactory 定义的 API 不难看出,只要能获得对应的实例,我们是可以手动的对非 spring 托管的 bean 进行依赖注入的。

3、分层配置工厂

BeanFactory 的三级接口为 ConfigurableBeanFactory,它实现了 HierarchicalBeanFactorySingletonBeanRegistry接口。

从字面上理解,它是一个可配置的 BeanFactory,它不仅支持 BeanFactory 分层,还支持以单例的方式操作 bean。它是整个 BeanFactory 体系中最重要的一环,通过这个接口,spring 通过该接口规定了一个 BeanFactory 应该具备以及可以从中获取哪些可配置的组件与参数。

这里我们先了解一下 SingletonBeanRegistry 接口,这个接口定义了容器根据名称注册或获取 bean 单例的能力:

public interface SingletonBeanRegistry {
    void registerSingleton(String beanName, Object singletonObject);
    Object getSingleton(String beanName);
    boolean containsSingleton(String beanName);
    String[] getSingletonNames();
    int getSingletonCount();
    Object getSingletonMutex();
}

然后回到 ConfigurableBeanFactory ,它在 HierarchicalBeanFactory 的基础上补充了大量的方法:

public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
	String SCOPE_SINGLETON = "singleton"; // 单例
	String SCOPE_PROTOTYPE = "prototype"; // 多例

	// 配置父工厂
	void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;
	
	// 配置类加载器
	void setBeanClassLoader(@Nullable ClassLoader beanClassLoader);
	ClassLoader getBeanClassLoader();
	void setTempClassLoader(@Nullable ClassLoader tempClassLoader);
	ClassLoader getTempClassLoader();
	
	// 配置bean元信息缓存
	void setCacheBeanMetadata(boolean cacheBeanMetadata);
	boolean isCacheBeanMetadata();
	
	// 配置bean配置的表达式解析器,用于提供@Value值注册等功能
	void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver);
	BeanExpressionResolver getBeanExpressionResolver();
	
	// 配置类型转换器
	void setConversionService(@Nullable ConversionService conversionService);
	ConversionService getConversionService();
	void setTypeConverter(TypeConverter typeConverter);
	TypeConverter getTypeConverter();
	
	// 配置属性注册表
	void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar);
	void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass);
	void copyRegisteredEditorsTo(PropertyEditorRegistry registry);
	
	// 配置字符串解析器,用于提供解析xml中的bean属性的表达式等功能
	void addEmbeddedValueResolver(StringValueResolver valueResolver);
	boolean hasEmbeddedValueResolver();
	String resolveEmbeddedValue(String value);
	
	// 配置bean的后置处理器BeanPostProcessor
	void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
	int getBeanPostProcessorCount();

	// 配置bean的作用域,接口中已经默认提供了单例或多例的scopeName
	void registerScope(String scopeName, Scope scope);
	String[] getRegisteredScopeNames();
	Scope getRegisteredScope(String scopeName);

	// 配置访问控制
	AccessControlContext getAccessControlContext();

	// 从其他的工厂复制配置
	void copyConfigurationFrom(ConfigurableBeanFactory otherFactory);

	// 给指定的bean注册别名
	void registerAlias(String beanName, String alias) throws BeanDefinitionStoreException;
	void resolveAliases(StringValueResolver valueResolver);
	
	// 合并bean的定义信息
	BeanDefinition getMergedBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	// 是否是工厂bean
	boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException;
	
	// 设置bean的创建状态,管理bean的依赖与被依赖关系,用于处理循环依赖等问题
	void setCurrentlyInCreation(String beanName, boolean inCreation);
	boolean isCurrentlyInCreation(String beanName);
	void registerDependentBean(String beanName, String dependentBeanName);
	String[] getDependentBeans(String beanName);
	String[] getDependenciesForBean(String beanName);

	// bean的销毁相关方法
	void destroyBean(String beanName, Object beanInstance);
	void destroyScopedBean(String beanName);
	void destroySingletons();
}

这个接口定义了非常多的 API,按照用途来说,这些 API 大概分为三类:

  • bean 的管理方法:包括 bean 依赖状态与生命周期的获取,bean 的销毁,bean 作用域域、定义信息与别名的操作;
  • bean 创建过程中使用组件的配置:包括字符串解析器,类加载器,类型转换器,属性注册表,bean 的后置处理器等组件的配置;
  • 工厂本身状态的一些操作:包括父工程配置,工厂间依赖的拷贝,以及访问控制等。

4、批量分层配置工厂

ConfigurableListableBeanFactoryBeanFactory 体系的第四级接口,也是最后一级接口。它继承了 ConfigurableBeanFactoryListableBeanFactoryAutowireCapableBeanFactory 接口,因此它具备到目前为止 BeanFactory 前三级接口定义的全部能力。

它表示了一个可以配置的,允许按单例或多例操作 bean,支持自动装配 bean,并且可以根据 bean 的名称、类型或者类上注解批量获取 bean 的超级 bean 工厂。

image-20220620150717261

它在上述功能的基础上,又针对各接口提供的功能定义了一些新的补充方法:

public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
    // 自动装配相关配置
    void ignoreDependencyType(Class<?> type);
    void ignoreDependencyInterface(Class<?> ifc);
    void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue);
    boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor) throws NoSuchBeanDefinitionException;
    
    // 获取bean的定义信息
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    
    // 获取已经定义的bean名称的迭代器
    Iterator<String> getBeanNamesIterator();
    // 清除bean元信息缓存
    void clearMetadataCache();
    
    // 冻结配置,冻结后工厂的配置不允许进一步修改
    void freezeConfiguration();
    boolean isConfigurationFrozen();
    
    // 实例化所有未实例化的单例bean
    void preInstantiateSingletons() throws BeansException;
}

二、ApplicationContext 接口体系

严格来说,ApplicationContextBeanFactory 的子类,或者说,BeanFactory 是其组成的一部分。但是由于其附加了很多 BeanFactory 所不具备的功能,因此一般将其与 BeanFactory 体系分开看待。

ApplicationContext 有 web 环境上下文与非 web 环境上下文的两个实现体系,单纯按接口层次分为三层:

  • 第一层:ApplicationContext
  • 第二层:WebApplicationContextConfigurableApplicationContext
  • 第三层:ConfigurableApplicationContext

image-20220620173854597

1、ApplicationContext

ApplicationContext 接口是基于 BeanFactory 的进一步实现,它同时实现了 EnvironmentCapableListableBeanFactoryHierarchicalBeanFactoryMessageSourceApplicationEventPublisher 以及 ResourcePatternResolver 接口。相较 BeanFactory ,它的功能要更加强大。

image-20220620142154578

ApplicationContext 继承的各个接口分别对应它提供各项功能:

  • HierarchicalBeanFactoryListableBeanFactory:提供像 BeanFactory 一样操作 bean 的功能;
  • ApplicationEventPublisher:提供向监听器发布事件的能力;
  • ResourcePatternResolverEnvironmentCapable:提供选择性的某个特定环境的文件资源中加载配置的能力;
  • MessageSource:提供解析消息并支持国际化配置的能力;

结合它提供的功能和它的名称,我们可以大概了解,与 BeanFactory 专门用于操作 bean 不同,ApplicationContext 用于提供 spring 程序在某个特定环境运行时所具备的全部信息的“上下文”对象,它之于 BeanFactory ,就像带各种功能的超级保温杯之于普通的水杯。

它定义的方法如下:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    // 获取上下文id
    String getId();
    // 获取对应应用程序名称
    String getApplicationName();
    // 获取上下文的展示名称
    String getDisplayName();
    // 获取容器被启动的时间
    long getStartupDate();
    // 获取父级上下文
    ApplicationContext getParent();
    // 获取自动装配bean工厂
    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

这里可以看到,虽然 ApplicationContext 没继承 AutowireCapableBeanFactory 接口,但是他依然可以通过方法获取到对应的装配工厂。

2、web 应用上下文与可配置上下文

WebApplicationContext

WebApplicationContext 是 web 环境的上下文,该上下文几乎没有可配置项,主要用于配置 Servlet 上下文:

public interface WebApplicationContext extends ApplicationContext {
    String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
    
    // 作用域
    String SCOPE_REQUEST = "request";
    String SCOPE_SESSION = "session";
    String SCOPE_APPLICATION = "application";
    
    // 固定的bean名称
    String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
    String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
    String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
    
    // 获取ServletContext
    ServletContext getServletContext();

}

ConfigurableApplicationContext

ConfigurableApplicationContext 表示一个可以配置的上下文容器,与 WebApplicationContext 不同,它提供了一些参数和属性的配置方法:

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
    
    String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
    String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
    String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
    String ENVIRONMENT_BEAN_NAME = "environment";
    String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
    String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
    String SHUTDOWN_HOOK_THREAD_NAME = "SpringContextShutdownHook";
    
    // 配置上下文的id
    void setId(String id);
    // 配置上下文父容器
    void setParent(@Nullable ApplicationContext parent);
    
    // 配置上下文允许环境
    void setEnvironment(ConfigurableEnvironment environment);
    @Override
    ConfigurableEnvironment getEnvironment();
    
    // 获取bean后置处理器
    void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
    
    // 添加一个应用监听器,用于监听ApplicationEventPublisher发布的事件
    void addApplicationListener(ApplicationListener<?> listener);
    
    // 配置类加载器
    void setClassLoader(ClassLoader classLoader);
    
    // 配置资源协议处理器
    void addProtocolResolver(ProtocolResolver resolver);
    
    // 刷新配置
    void refresh() throws BeansException, IllegalStateException;
    
    // 关闭此上下文容器时的回调函数
    void registerShutdownHook();
    
    // 关闭上下文容器,并释放资源
    void close();
    
    // 当前容器是否已经调用过refresh(),并且尚未关闭
    boolean isActive();
    
    // 获取bean工厂
    ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

}

它有一个通用可配置上下文的实现类:GenericApplicationContext,在非 web 环境中,该实现类的两个子类是最经常用到的:

  • GenericXmlApplicationContext:基于 xml 配置文件配置的上下文;
  • AnnotationConfigApplicationContext:基于注解配置的上下文;

3、可配置的web应用上下文

ConfigurableApplicationContext 接口同时继承了 WebApplicationContextConfigurableApplicationContext,代表了一个可以配置的 web 上下文容器:

public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext {

	String APPLICATION_CONTEXT_ID_PREFIX = WebApplicationContext.class.getName() + 
	String SERVLET_CONFIG_BEAN_NAME = "servletConfig";

	// 配置Servlet容器
	void setServletContext(@Nullable ServletContext servletContext);
	void setServletConfig(@Nullable ServletConfig servletConfig);
	@Nullable
	ServletConfig getServletConfig();

    // 设置命名空间
	void setNamespace(@Nullable String namespace);
	@Nullable
	String getNamespace();
	
	// 设置配置文件的路径,比如WEB-INF
	void setConfigLocation(String configLocation);
	void setConfigLocations(String... configLocations);
	@Nullable
	String[] getConfigLocations();

}

一般 web 环境下实例化的上下文都为该接口的实例。

三、总结

在 spring 中,容器分为两大类:BeanFactoryApplicationContext

BeanFactory

其中,BeanFactory 是纯粹的用于管理 bean 对象生命周期的容器,它的接口体系分为四层:

  1. BeanFactory 接口本身,是容器的最高层抽象;

  2. HierarchicalBeanFactory :分层工厂,表示一个存在层级关系的容器;

    ListableBeanFactory:批量工厂,表示一个允许根据名称、类型或类注解等属性批量的操作 bean 的容器;

    AutowireCapableBeanFactory:自动装配工厂,表示一个可以关联需要自动装配的 bean 的容器;

  3. ConfigurableBeanFactory:分层配置工厂 ,是 HierarchicalBeanFactorySingletonBeanRegistry 接口的组合,表示一个分层的、可以以单例模式操作 bean,并且允许调整配置的容器;

  4. ConfigurableListableBeanFactory:可配置的批量工厂,是ConfigurableBeanFactoryAutowireCapableBeanFactory 接口的组合,具备 BeanFactory 体系中的全部能力。

ApplicationContext

ApplicationContext 是基于 BeanFactory 的扩展,它实现了其他的接口,因此具有一些 BeanFactory 不具备的功能:

  • ApplicationEventPublisher:提供向监听器发布事件的功能;
  • ResourcePatternResolverEnvironmentCapable:提供选择性的某个特定环境的文件资源中加载配置的功能;
  • MessageSource:提供解析消息并支持国际化配置的功能;

从层次来说,ApplicationContext 主要分为三层:

  1. ApplicationContext 接口本身,是基于 BeanFactory 接口的扩展,是整个应用上下文体系的最顶层接口;

  2. WebApplicationContext:web 应用上下文,用于承载 ServletContext

    ConfigurableApplicationContext:用于非 web 环境下的可配置应用上下文;

  3. ConfigurableApplicationContext:可配置的 web 应用上下文,同时继承了 WebApplicationContextConfigurableApplicationContext 接口,代表了一个可以配置的 web 上下文容器。

    在一般的 web 环境中启动的都是该上下文的实例。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/170762.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 勤快的love枫[ZJOI2007]

    勤快的love枫[ZJOI2007]

  • android释放内存的一个办法

    step1:定义一个监听接口step2:androidapplication文件中添加如下代码//初始化//注册监听//内存空间过低的时候,被系统调用step3:那些浪费内存的地方,

    2021年12月27日
  • Pycharm中Debug的基本用法和高级技巧

    Pycharm中Debug的基本用法和高级技巧今天测试自己写的代码,测试了很多次都是实际结果与心里预测不相符,甚至一度怀疑Pycharm除了问题,哈哈。最后debug了一下,才发现是自己的操作问题才导致了错误的结果,看来Debug真的是个好侦探,让你不会乱怀疑。下面就和大家分享一下我在Pycharm上Debug的心得1.在Pycharm中打开一个.py文件,并设置断点鼠标左键单击箭头处需要设置断点的语句即可设置断点2.运行debug…

  • flash怎么强制gc_Adode Flash初级教程

    flash怎么强制gc_Adode Flash初级教程AdodeFlash初级教程(湖南信息职业技术学院xxgc.hniu.cn教务处,湖南长沙410200)第一章入门一、概述1、定义:矢量二维动画2、适用范围:1.针对与网页2.动漫3、特点:a矢量动画制作模式,文件容量小b支持多类型文件导入(图片、视频、音频)c支持流媒体技术d交互动画4、网页四剑客简介adobedreamweaver:是一个网页排版软件,不是设计软件,唯一体现设计软件的地方是c…

  • Skeleton Screen — 骨架屏–应用

    Skeleton Screen — 骨架屏–应用Skeleton Screen — 骨架屏–应用

  • Databus for Oracle

    Databus for OracleDatabus组成Relay:数据抓取端读取数据源变更行(ROW),并将变更行数据序列化到内存缓冲区。监听客户端请求并传输缓冲区的数据。Client:数据客户端检查Relay端的数据变更,并同步数据。如果与Relay之间数据变更相差太大、会执行追溯功能。注:单个客户端既可以处理全部Databus数据流,也可以作为集群的一部分处理一小部分数据流。bootstrap-pr…

    2022年10月16日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号