Spring源码解析:BeanFactory深入理解

2023-10-27

(现在一般都用ApplicantContext代替BeanFactory)

说到Spring框架,人们往往大谈特谈一些似乎高逼格的东西,比如依赖注入,控制反转,面向切面等等。但是却忘记了最基本的一点,Spring的本质是一个bean工厂(beanFactory)或者说bean容器,它按照我们的要求,生产我们需要的各种各样的bean,提供给我们使用。只是在生产bean的过程中,需要解决bean之间的依赖问题,才引入了依赖注入(DI)这种技术。也就是说依赖注入是beanFactory生产bean时为了解决bean之间的依赖的一种技术而已。

那么我们为什么需要Spring框架来给我们提供这个beanFactory的功能呢?原因是一般我们认为是,可以将原来硬编码的依赖,通过Spring这个beanFactory这个工厂来注入依赖,也就是说原来只有依赖方和被依赖方,现在我们引入了第三方——spring这个beanFactory,由它来解决bean之间的依赖问题,达到了松耦合的效果;这个只是原因之一,还有一个更加重要的原因:在没有spring这个beanFactory之前,我们都是直接通过new来实例化各种对象,现在各种对象bean的生产都是通过beanFactory来实例化的,这样的话,spring这个beanFactory就可以在实例化bean的过程中,做一些小动作——在实例化bean的各个阶段进行一些额外的处理,也就是说beanFactory会在bean的生命周期的各个阶段中对bean进行各种管理,并且spring将这些阶段通过各种接口暴露给我们,让我们可以对bean进行各种处理,我们只要让bean实现对应的接口,那么spring就会在bean的生命周期调用我们实现的接口来处理该bean。下面我们看是如何实现这一点的。

1. bean容器的启动

bean在实例化之前,必须是在bean容器启动之后。所以就有了两个阶段:

1)bean容器的启动阶段;

2)容器中bean的实例化阶段;

在启动阶段

1> 首先是读取bean的xml配置文件,然后解析xml文件中的各种bean的定义,将xml文件中的每一个<bean />元素分别转换成一个BeanDefinition对象,其中保存了从配置文件中读取到的该bean的各种信息:

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
        implements BeanDefinition, Cloneable {
    private volatile Object beanClass;
    private String scope = SCOPE_DEFAULT;
    private boolean abstractFlag = false;
    private boolean lazyInit = false;
    private int autowireMode = AUTOWIRE_NO;
    private int dependencyCheck = DEPENDENCY_CHECK_NONE;
    private String[] dependsOn;
    private ConstructorArgumentValues constructorArgumentValues;
    private MutablePropertyValues propertyValues;
    private String factoryBeanName;
    private String factoryMethodName;
    private String initMethodName;
    private String destroyMethodName;
}

beanClass保存bean的class属性,scop保存bean是否单例,abstractFlag保存该bean是否抽象,lazyInit保存是否延迟初始化,autowireMode保存是否自动装配,dependencyCheck保存是否坚持依赖,dependsOn保存该bean依赖于哪些bean(这些bean必须提取初始化),constructorArgumentValues保存通过构造函数注入的依赖,propertyValues保存通过setter方法注入的依赖,factoryBeanName和factoryMethodName用于factorybean,也就是工厂类型的bean,initMethodName和destroyMethodName分别对应bean的init-method和destory-method属性,比如:

<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" 
      init-method="init" destroy-method="close">

读完配置文件之后,得到了很多的BeanDefinition对象,

2> 然后通过BeanDefinitionRegistry将这些bean注册到beanFactory中:

public interface BeanDefinitionRegistry extends AliasRegistry {
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws 
    BeanDefinitionStoreException;
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    boolean containsBeanDefinition(String beanName);
    String[] getBeanDefinitionNames();
    int getBeanDefinitionCount();
    boolean isBeanNameInUse(String beanName);
}

BeanFactory的实现类,需要实现BeanDefinitionRegistry 接口:

@SuppressWarnings("serial")
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    /** Map of bean definition objects, keyed by bean name */
    private final Map<String, BeanDefinition> beanDefinitionMap = new 
                 ConcurrentHashMap<String, BeanDefinition>(64);
    
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
        // ... ...
       this.beanDefinitionMap.put(beanName, beanDefinition);
       // ... ...
    }
}

我们看到BeanDefinition被注册到了 DefaultListableBeanFactory, 保存在它的一个ConcurrentHashMap中。

将BeanDefinition注册到了beanFactory之后,在这里Spring为我们提供了一个扩展的切口,允许我们通过实现接口BeanFactoryPostProcessor 在此处来插入我们定义的代码:

public interface BeanFactoryPostProcessor {
    /**
     * Modify the application context's internal bean factory after its standard
     * initialization. All bean definitions will have been loaded, but no beans
     * will have been instantiated yet. This allows for overriding or adding
     * properties even to eager-initializing beans.
     * @param beanFactory the bean factory used by the application context
     * @throws org.springframework.beans.BeansException in case of errors
     */
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws 
        BeansException;
}

典型的例子就是:PropertyPlaceholderConfigurer,我们一般在配置数据库的dataSource时使用到的占位符的值,就是它注入进去的:

 

public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
        implements BeanFactoryPostProcessor, PriorityOrdered {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws     
        BeansException {
        try {
            Properties mergedProps = mergeProperties();
            // Convert the merged properties, if necessary.
            convertProperties(mergedProps);
            // Let the subclass process the properties.
            processProperties(beanFactory, mergedProps);
        }
        catch (IOException ex) {
            throw new BeanInitializationException("Could not load properties", ex);
        }
    }
}

processProperties(beanFactory, mergedProps);在子类中实现的,功能就是将 ${jdbc_username}等等这些替换成实际值。

<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" 
         init-method="init" destroy-method="close">
        <property name="url" value="${jdbc_url}" />
        <property name="username" value="${jdbc_username}" />
        <property name="password" value="${jdbc_password}" />
</bean>
 

2、bean的实例化阶段

实例化阶段主要是通过反射或者CGLIB对bean进行实例化,在这个阶段Spring又给我们暴露了很多的扩展点:

1> 各种的Aware接口,比如 BeanFactoryAware,MessageSourceAware,ApplicationContextAware

对于实现了这些Aware接口的bean,在实例化bean时Spring会帮我们注入对应的:BeanFactory, MessageSource,ApplicationContext的实例:

public interface BeanFactoryAware extends Aware {
    /**
     * Callback that supplies the owning factory to a bean instance.
     * <p>Invoked after the population of normal bean properties
     * but before an initialization callback such as
     * {@link InitializingBean#afterPropertiesSet()} or a custom init-method.
     * @param beanFactory owning BeanFactory (never {@code null}).
     * The bean can immediately call methods on the factory.
     * @throws BeansException in case of initialization errors
     * @see BeanInitializationException
     */
    void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
public interface ApplicationContextAware extends Aware {
    /**
     * Set the ApplicationContext that this object runs in.
     * Normally this call will be used to initialize the object.
     * <p>Invoked after population of normal bean properties but before an init callback such
     * as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
     * or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
     * {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
     * {@link MessageSourceAware}, if applicable.
     * @param applicationContext the ApplicationContext object to be used by this object
     * @throws ApplicationContextException in case of context initialization errors
     * @throws BeansException if thrown by application context methods
     * @see org.springframework.beans.factory.BeanInitializationException
     */
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
public interface MessageSourceAware extends Aware {
    /**
     * Set the MessageSource that this object runs in.
     * <p>Invoked after population of normal bean properties but before an init
     * callback like InitializingBean's afterPropertiesSet or a custom init-method.
     * Invoked before ApplicationContextAware's setApplicationContext.
     * @param messageSource message sourceto be used by this object
     */
    void setMessageSource(MessageSource messageSource);
}

2> BeanPostProcessor接口

实现了BeanPostProcessor接口的bean,在实例化bean时Spring会帮我们调用接口中的方法:

public interface BeanPostProcessor {
    /**
     * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
     * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
     * or a custom init-method). The bean will already be populated with property values.
     * The returned bean instance may be a wrapper around the original.*/
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    /**
     * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
     * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
     * or a custom init-method). The bean will already be populated with property values.
     * The returned bean instance may be a wrapper around the original.*/
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

从注释中可以知道 postProcessBeforeInitialization方法在 InitializingBean接口的 afterPropertiesSet方法之前执行,而postProcessAfterInitialization方法在 InitializingBean接口的afterPropertiesSet方法之后执行。

3> InitializingBean接口

实现了InitializingBean接口的bean,在实例化bean时Spring会帮我们调用接口中的方法:

public interface InitializingBean {
    /**
     * Invoked by a BeanFactory after it has set all bean properties supplied
     * (and satisfied BeanFactoryAware and ApplicationContextAware).
     * <p>This method allows the bean instance to perform initialization only
     * possible when all bean properties have been set and to throw an
     * exception in the event of misconfiguration.
     * @throws Exception in the event of misconfiguration (such
     * as failure to set an essential property) or if initialization fails.
     */
    void afterPropertiesSet() throws Exception;
}

 

 4> DisposableBean接口

实现了BeanPostProcessor接口的bean,在该bean死亡时Spring会帮我们调用接口中的方法:

public interface DisposableBean {
    /**
     * Invoked by a BeanFactory on destruction of a singleton.
     * @throws Exception in case of shutdown errors.
     * Exceptions will get logged but not rethrown to allow
     * other beans to release their resources too.
     */
    void destroy() throws Exception;
}

 

 InitializingBean接口 和 DisposableBean接口对应于 <bean /> 的 init-method 和 destory-method 属性,其经典的例子就是dataSource:

<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">

所以在Spring初始化 dataSource 这个bean之后会调用 DruidDataSource.init 方法:

 

public void init() throws SQLException {
        // ... ...try {
            lock.lockInterruptibly();
        } catch (InterruptedException e) {
            throw new SQLException("interrupt", e);
        }
        boolean init = false;
        try {  
            connections = new DruidConnectionHolder[maxActive];
            SQLException connectError = null;
            try {                
                for (int i = 0, size = getInitialSize(); i < size; ++i) {
                    Connection conn = createPhysicalConnection();
                    DruidConnectionHolder holder = new DruidConnectionHolder(this, conn);
                    connections[poolingCount++] = holder;
                }
                if (poolingCount > 0) {
                    poolingPeak = poolingCount;
                    poolingPeakTime = System.currentTimeMillis();
                }
            } catch (SQLException ex) {
                LOG.error("init datasource error", ex);
                connectError = ex;
            }          
        } catch (SQLException e) {
            LOG.error("dataSource init error", e);
            throw e;
        } catch (InterruptedException e) {
            throw new SQLException(e.getMessage(), e);
        } finally {
            inited = true;
            lock.unlock();
        }
    }

基本就是初始化数据库连接池。

在dataSource 这个bean死亡时会调用 DruidDataSource.close()方法:

public void close() {
        lock.lock();
        try {
          for (int i = 0; i < poolingCount; ++i) {
                try {
                    DruidConnectionHolder connHolder = connections[i];
                    for (PreparedStatementHolder stmtHolder : 
                        connHolder.getStatementPool().getMap().values()) {
                        connHolder.getStatementPool().closeRemovedStatement(stmtHolder);
                    }
                    connHolder.getStatementPool().getMap().clear();
                    Connection physicalConnection = connHolder.getConnection();
                    physicalConnection.close();
                    connections[i] = null;
                    destroyCount.incrementAndGet();
                } catch (Exception ex) {
                    LOG.warn("close connection error", ex);
                }
            }          
        } finally {
            lock.unlock();
        }
    }

基本就是关闭连接池中的连接。

另外注解 @PostConstruct 和 @PreDestroy 也能达到 InitializingBean接口 和 DisposableBean接口的效果。

 

3、 总结

spring容器接管了bean的实例化,不仅仅是通过依赖注入达到了松耦合的效果,同时给我们提供了各种的扩展接口,来在bean的生命周期的各个时期插入我们自己的代码:

0)BeanFactoryPostProcessor接口(在容器启动阶段)

1)各种的Aware接口

2)BeanPostProcessor接口

3)InitializingBean接口(@PostConstruct, init-method)

4)DisposableBean接口(@PreDestroy, destory-method)

3. FactoryBean接口

实现了FactoryBean接口的bean是一类叫做factory的bean。其特点是,spring会在使用getBean()调用获得该bean时,会自动调用该bean的getObject()方法,所以返回的不是factory这个bean,而是这个bean.getOjbect()方法的返回值

public interface FactoryBean<T> {
    T getObject() throws Exception;
    Class<?> getObjectType();
    boolean isSingleton();
}

典型的例子有spring与mybatis的结合:

  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
      <property name="dataSource" ref="dataSource" />
      <property name="configLocation" value="classpath:config/mybatis-config-master.xml" />
      <property name="mapperLocations" value="classpath*:config/mappers/master/**/*.xml" />
    </bean>

我们看上面该bean,因为实现了FactoryBean接口,所以返回的不是 SqlSessionFactoryBean 的实例,而是它的 SqlSessionFactoryBean.getObject() 的返回值:

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, 
   InitializingBean, ApplicationListener<ApplicationEvent> {

  private static final Log logger = LogFactory.getLog(SqlSessionFactoryBean.class);

  private Resource configLocation;

  private Resource[] mapperLocations;

  private DataSource dataSource;
  
  public SqlSessionFactory getObject() throws Exception {
    if (this.sqlSessionFactory == null) {
      afterPropertiesSet();
    }

    return this.sqlSessionFactory;
  }

其实他是一个专门生产 sqlSessionFactory 的工厂,所以才叫 SqlSessionFactoryBean。 而SqlSessionFactory又是生产SqlSession的工厂。

还有spring与ibatis的结合:

 <!-- Spring提供的iBatis的SqlMap配置 -->
    <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="configLocation" value="classpath:sqlmap/sqlmap-config.xml" />
        <property name="dataSource" ref="dataSource" />
    </bean>
public class SqlMapClientFactoryBean implements FactoryBean<SqlMapClient>, InitializingBean {
    private Resource[] configLocations;
    private Resource[] mappingLocations;
    private Properties sqlMapClientProperties;
    private DataSource dataSource;
    private boolean useTransactionAwareDataSource = true;
    private Class transactionConfigClass = ExternalTransactionConfig.class;
    private Properties transactionConfigProperties;
    private LobHandler lobHandler;
    private SqlMapClient sqlMapClient;
    public SqlMapClient getObject() {
        return this.sqlMapClient;
    }
 

SqlMapClientFactoryBean 返回的是 getObject() 中返回的 sqlMapClient, 而不是 SqlMapClientFactoryBean 自己的实例。

4. 依赖注入(DI)

1) 依赖注入的方式分为构造函数注入和setter方法注入:

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg index="0" value="7500000"/>
    <constructor-arg index="1" ref="bar"/>
</bean>
<bean id="bar" class="x.y.Bar"/>

构造函数注入使用:<constructor-arg index="0" value="7500000"/>, <constructor-arg type="int" value="7500000"/>,对于非简单参数,需要使用ref <constructor-arg index="1" ref="bar"/>

 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
      <property name="dataSource" ref="dataSource" />
      <property name="configLocation" value="classpath:config/mybatis-config.xml" />
      <property name="mapperLocations" value="classpath*:config/mappers/**/*.xml" />
 </bean>

setter方法注入使用 <property name="username" value="xxx"/>, 非简单类型属性使用ref <property name="xxbean" ref="xxx"/>

2)集合等复杂类型的注入:

<bean id="moreComplexObject" class="example.ComplexObject">
    <!-- results in a setAdminEmails(java.util.Properties) call -->
    <property name="adminEmails">
        <props>
            <prop key="administrator">administrator@example.org</prop>
            <prop key="support">support@example.org</prop>
            <prop key="development">development@example.org</prop>
        </props>
    </property>
    <!-- results in a setSomeList(java.util.List) call -->
    <property name="someList">
        <list>
            <value>a list element followed by a reference</value>
            <ref bean="myDataSource" />
        </list>
    </property>
    <!-- results in a setSomeMap(java.util.Map) call -->
    <property name="someMap">
        <map>
            <entry key="an entry" value="just some string"/>
            <entry key ="a ref" value-ref="myDataSource"/>
        </map>
    </property>
    <!-- results in a setSomeSet(java.util.Set) call -->
    <property name="someSet">
        <set>
            <value>just some string</value>
            <ref bean="myDataSource" />
        </set>
    </property>
</bean>

也很简单,list属性就是 <list>里面包含<value>或者<ref>或者<bean>, set也类似。map是<map>里面包含<entry>这个也好理解,因为map的实现就是使用内部类Entry来存储key和value. Properties是 <props>里面包含<prop>.

5. <bean> 元素可以配置的属性:

<bean> 除了 id 和 class 属性之外,还有一些可选的属性:

1) scope属性,默认<bean> 的 scope就是 singleton="true", springmvc和struts2的重要区别之一就是spring的controll是单例的,而struts2的action是:scope="prototype" ,还有 scope="request" , scope="session",scope="globalSession"(仅用于portlet)

2)abstract属性,是否是抽象的bean:

<bean id="baseDAO" abstract="true">
        <property name="dataSource" ref="dataSource" />
        <property name="sqlMapClient" ref="sqlMapClient" />
</bean>
    
<bean id="collectionDAO" class="net.minisns.dal.dao.CollectionDAOImpl" 
parent="baseDAO" />

<bean id="commentDAO" class="net.minisns.dal.dao.CommentDAOImpl" parent="baseDAO" />

3)depends-on 依赖于某个bean,其必须先初始化:<bean id="xxx" class="xxx" depends-on="refbean" />

4)lazy-init="true" 是否延迟初始化,默认为 false

5) dependency-check 是否对bean依赖的其它bean进行检查,默认值为 none,可取值有:none, simple, object, all等

6)factory-method 和 factory-bean用于静态工厂和非静态工厂:

<bean id="bar" class="...StaticBarInterfaceFactory" factory-method="getInstance"/>
<bean id="barFactory" class="...NonStaticBarInterfaceFactory"/> 
<bean id="bar" factory-bean="barFactory" factory-method="getInstance"/>

7)init-method, destory-method 指定bean初始化和死亡时调用的方法,常用于 dataSource的连接池的配置

8) lookup-method 方法注入:

<bean id="newsBean" class="..xxx" singleton="false"> 
<bean id="mockPersister" class="..impl.MockNewsPersister">
  <lookup-method name="getNewsBean" bean="newsBean"/> 
</bean>  

表示 mockPersister 有一个依赖属性 newsBean,该属性的每次注入都是通过调用newsBean.getNewsBean() 方法获得的。

9) autowire 是否启用自动装配依赖,默认为 no, 其它取值还有:byName, byType, constructor

原文链接:http://www.cnblogs.com/digdeep/p/4518571.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring源码解析:BeanFactory深入理解 的相关文章

  • WSL重启方法

    WSL Ubuntu18 04 LTS 重启方法 以管理员权限运行cmd gt gt net stop LxssManager 停止 gt gt net start LxssManager 启动
  • 抓取一闪而过的提示消息文本

    前端业务操作出现一闪而过的message提示信息 它们有一个特点就是显示1 2s后会自动消失 例如下图1 图1 这些消息不像 alert 警告框 confirm 确认框 和prompt 提示框 那样 需要用户手动点击确定或取消按钮后才消失
  • 华为od机考真题-HJ32密码截取(中等)

    求最大回文子串 while 1 try str1 input if len str1 1 print 1
  • 渗透测试学习目录

    网络攻击防范 课程介绍 1 HTML 01 HTML标签和文本属性 02 form表单 input 标签 属性 03 a标签 img标签 table标签 04 无序列表和有序列表 05 frameset frame 框架的使用 2 div
  • VS离线安装NuGet包

    VS离线安装NuGet包 以VS 2017为例 一 下载NuGet包 官方NuGet包下载网址 https www nuget org 1 搜索需要下载的包名称 点击进入包详情页面 2 点击Download package 下载离线包 3
  • [NOI2011]阿狸的打字机【AC自动机fail树+树状数组】

    题目链接 P2414 题目给出N个字符串 我们现在想知道的是第x个字符串在第y个字符串中出现的次数是多少次 求每个字符在其余字符中出现次数 想到从AC自动机上走 其实可以看作是求它的后缀的前缀中有多少个是满足的 换言之 我们可以去fail树
  • 日前日内多阶段多时间尺度源荷储协调调度(matlab代码)

    多阶段多时间尺度的源荷储协调调度的优势是考虑新能源出力的波动性与随机性 减少需求响应负荷的不确定性会对电网制定的日前调度计划准确性的影响 也就是能够更加精准的进行调度和分析 优化结果的可用性更强 在这方面论文里面 金力的 考虑特性分布的储能
  • 如何利用excel中的数据源制作数据地图

    关于这个问题 制作数据地图的方法已不新奇 总体来说有这么几类方案 一类方案 直接在excel里制作 优势 个人小数据量应用较为方便简单 缺点 需要熟悉VBA 且更强大的功能对VBA水平要求较高 1 绘制地图图形 VBA宏语言 思路 用插入图
  • MOS管相关知识

    MOS管 MOS管的英文全称叫MOSFET Metal Oxide Semiconductor Field Effect Transistor 即金属氧化物半导体型场效应管 属于场效应晶体管中的绝缘栅型 MOS管是场效应管的一种 在一般电子
  • 版本号自动生成方法

    只需把 AssemblyInfo cs文件中的 assembly AssemblyVersion 1 0 0 0 改成 assembly AssemblyVersion 1 0 另外还需要把 assembly AssemblyFileVer
  • 什么是负载均衡,看完文章秒懂

    一 负载均衡简介 1 1 大型网站面临的挑战 大型网站都要面对庞大的用户量 高并发 海量数据等挑战 为了提升系统整体的性能 可以采用垂直扩展和水平扩展两种方式 垂直扩展 在网站发展早期 可以从单机的角度通过增加硬件处理能力 比如 CPU 处
  • 运行时报错“version `GLIBCXX_3.4.29‘ not found”底层原理分析

    文章目录 1 报错的现象 2 为什么程序有的报找不到某个版本的动态库 有的报找不到动态库文件 2 1 找不到动态库 2 2 找不到某个版本的动态库 2 2 1 报错的原因 2 2 2 动态库的版本是如何指定的 程序又是如何记录依赖的动态库版
  • DecimalField的使用

    DecimalField 类 DecimalField max digits 无 decimal places 无 选项 固定精度的十进制数 在Python中表示一个 十进制的实例 有两个必需的参数 DecimalField max dig
  • 浏览器插件下载“Download failed. Please check your connection.”解决方法

    第一步 查看错误原因 Download failed Please check your connection 下载失败 请检查您的连接 第二步 根据问题根源查看connects相关设置 第三步 分析原因 我是开启了Manual proxy
  • NeRF必读:Instant-NGP----RTX3090单卡就能玩转NeRF

    前言 NeRF从2020年发展至今 仅仅三年时间 而Follow的工作已呈井喷之势 相信在不久的将来 NeRF会一举重塑三维重建这个业界 甚至重建我们的四维世界 开头先吹一波 NeRF的发展时间虽短 有几篇工作却在我研究的领域开始呈现万精油
  • C语言---双向链表(详解)---数据结构

    双向链表所需要头文件 首先重定义类型名 意义我前几篇讲过几次了 这里就不在赘述了 顺序表 单链表的开头都有说明 然后我们需要一个结构体 结构体包含 存储数据的 a 指向一个节点的指针 next 指向上一个节点的指针 prve 双向链表实现的
  • pgadmin4更改数据类型和主键

    在 pgAdmin 4 中更改数据类型和主键需要以下步骤 打开 pgAdmin 4 连接到您想要修改的数据库 找到并打开您想要修改的表 单击该表后单击 设计 按钮 找到要修改的列 单击该列后单击 编辑 删除 按钮 在弹出的窗口中 更改 数据
  • hai子兄弟表示法(C语言实现)——树的存储结构

    孩子兄弟表示法实际就是创建一棵二叉树 include

随机推荐

  • 统计中位数为 K 的子数组

    给你一个长度为n的数组nums 该数组由从1 到n的不同整数组成 另给你一个正整数k 统计并返回nums中的 中位数等于k的非空子数组的数目 注意 数组的中位数是按递增顺序排列后位于中间的那个元素 如果数组长度为偶数 则中位数是位于中间靠左
  • 音频系统POP音的原理和解决方法

    音频系统POP音的原理和解决方法 目录 文章目录 音频系统POP音的原理和解决方法 目录 音频IC与功放IC的电源时序与功能模块使能时序 功放IC输入端INP与INN的阻抗匹配 增大VBIAS滤波电容 BTL输出和SE输出 减小输出端耦合电
  • JWT令牌验证

    目录 一 JWT介绍 二 安装依赖 三 登陆接口 1 令牌工具类 2 接口代码 四 说明 一 JWT介绍 JWT全称 JSON Web Token 官网 JSON Web Tokens jwt io 定义了一种简洁的 自包含的格式 用于在通
  • Cortex-M3/M4内核STM32的LR寄存器和PC寄存器

    文章目录 怎么控制STM32跳转到指定程序 STM32的LR寄存器和PC寄存器 结语 怎么控制STM32跳转到指定程序 首先 使用标号加goto语句可以使程序强制跳转 而goto的原理实际上是汇编语言里面的强制跳转 我们看STM32的启动文
  • 顺序表企业级应用

    高并发 WEB 服务器中顺序表的应用 高性能的 web 服务器 Squid 每秒可处理上万并发的请求 从网络连接到服务器的客 户端与服务器端在交互时会保持一种会话 和电话通话的场景类似 服务器端为了管 理好所有的客户端连接 给每个连接都编了
  • PARL 强化学习框架学习

    最近参加了百度的的PARL深度强化学习课程 算是对强化学习有了一定了解 因为之前并没有学习过强化学习相关的知识 粗略入门 体验了PARL框架 确实对新手比较友好 入门学习了比较基础的算法 如SARSA Q Learning DQN PG D
  • Matlab 2020b 64bit

    Matlab 2020b 64bit 链接 https pan baidu com s 1PfAaWPGEzyXBBvYWe48Fng pwd kigc 提取码 kigc 来自百度网盘超级会员V7的分享
  • 数据结构之线性表(bsd, sys/queue.h)

    数据结构之线性表 Author Once Day Date 2023年5月27日 参考文档 Linux内嵌链表 sys queue h 详解 tissar的博客 CSDN博客 嵌入式大杂烩周记第 3 期 sys queue h 知乎 zhi
  • AIC(最小信息化准则)

    AIC信息准则 即Akaike information criterion 是用来衡量统计模型拟合优良性的一个标准 是是由日本统计学家赤池弘次创立和发展的 因此也称为赤池信息量准则 它建立在熵的概念基础上 可以权衡所估计模型的复杂度和模型拟
  • 去除vue顶部60px的空白

    问题 今天才注意到编译后的vue代码 在网站的顶部有一个margin top 60px的空白 有点不解 于是去看源码 代码 app font family Avenir Helvetica Arial sans serif webkit f
  • 概率统计21——指数分布和无记忆性

    指数分布 Exponential distribution 是一种连续型概率分布 可以用来表示独立随机事件发生的时间间隔的概率 比如婴儿出生的时间间隔 旅客进入机场的时间间隔 打进客服中心电话的时间间隔 系统出现bug的时间间隔等等 指数分
  • 给rhel9、centos-stream9 设置软件源

    我使用的是清华镜像源 https mirrors tuna tsinghua edu cn centos stream SIGs 9 stream 一 软件源添加 vim etc yum repos d CentOS Stream9 rep
  • typedef struct node的用法及与struct node的区别,为何要用typedef?

    typedef的作用是为已有的数据类型定义一个新名字 其主要目的是为了我们在使用时能用这个更加清晰简单的新名字 还有一个目的就是为了简化变量的声明 下面的几段代码具有相同的功能 都是用于链表结构体节点的定义和声明 第一种方式 struct
  • vue页面刷新或者后退参数丢失的问题

    在toB的项目中 会经常遇到列表数据筛选查询的情景 当要打开某一项的详情页或者暂时离开列表页 再返回 后退时 选择的筛选条件会全部丢失 辛辛苦苦选择好的条件全没了 还得重新选择 如果有分页的更头大 还得重新一页页翻到之前看到的那一页 用户体
  • 如何理解协方差矩阵(散布矩阵)

    这学期开了模式识别的学习课程 经常提到概率论与数理统计的一个概念 协方差矩阵 在模式识别中又叫散布矩阵 理解这个矩阵严格意义上来说其实不需要太多先导知识 我们只需要了解一些线性代数基本的概念 但是你如果不了解协方差矩阵 听模式识别的课程就会
  • 有深度的文章

    大家好 时隔半年 我将会继续更新推文 主发微信公众号 希望与大家一起交流学习 望大家多支持 你将在这里以最短的时间 获得最好的技术知识 图片是公众号二维码 谢谢大家
  • 第五章字符串总结

    5 1 String类 5 1 1 声明字符串 字符串是常量 它们可以显示任何文字信息 字符串的值在创建之后不能更改 在 Java 语言中 单引号中的内容表示字符 例如 s 而双引号中的内容则表示字符串 例如 我是字符串 123456789
  • vlc-android配置实录

    听说vlc底层也用的ffmpeg 免费开源的 业界做的不错的 就来看看 从网上找了很多例子 也从github上找了好多demo 好多都不全 或者下载下来编译失败 官网上下载的vlc android就编译失败 下面列两个可以用的 一 有vlc
  • JavaScript实现数组对应位置插入另一个数组

    系列文章目录 文章目录 系列文章目录 前言 一 使用循环遍历 二 使用concat和slice方法 三 使用splice方法 四 使用for循环 总结 前言 在JavaScript中 有时我们需要将一个数组的元素按照对应位置插入另一个数组中
  • Spring源码解析:BeanFactory深入理解

    现在一般都用ApplicantContext代替BeanFactory 说到Spring框架 人们往往大谈特谈一些似乎高逼格的东西 比如依赖注入 控制反转 面向切面等等 但是却忘记了最基本的一点 Spring的本质是一个bean工厂 bea