Springboot Bean创建流程、三种Bean注入方式(构造器注入、字段注入、setter注入)、循坏依赖问题

Spring——Bean注入几种方式(放入容器) Spring系列初体验,使用Spring怎么能不知道这几种将Bean放入容器中的方法呢?XML、注解、实现接口.. 阅读详情
文章目录

1 Bean 创建流程

简单来说,当容器里要放的Bean很多时,Spring会优先创建依赖最少的Bean。本文主要考虑单例模式。

1.1 Bean的扫描注册

Spring启动后首先会根据SpringbootApplication的包扫描配置扫描包里的所有文件,然后将使用了注解标记的类(如@Component、@Service、@Repository、@Configuration等)和xml文件里定义的Bean生成BeanDefinition对象注册到上下文ApplicationContext中,该对象包括Bean的名称、类型、作用域、构造函数参数、依赖等信息。

1.2 创建Bean的顺序
1.2.1 存在依赖关系

Spring在创建Bean之前会先通过BeanDefinition分析Bean之间的依赖关系,通常使用有向无环图DAG构建,若BeanA依赖BeanB那么会有一条由BeanB指向BeanA的有向边。根据DAG获得拓扑排序,优先对入度为0(或最少)的Bean节点初始化,这样才能尽量确保在创建某个Bean时,它依赖的Bean已经存在。

在创建Bean的时候,Spring仍会检查它需要的依赖是否已经存在,如果存在则直接注入,如果依赖Bean还没创建,那么会去递归创建依赖的Bean,直到所有依赖都被创建,再创建当前Bean。

1.2.2 不存在依赖关系

对于不存在依赖关系的Bean,Spring会按照以下顺序加载Bean:

  • XML配置文件里按照Bean的定义顺序加载;
  • @ComponentScan及其子注解(@Component、@Service、@Repository)声明的Bean按照字母顺序加载;
  • 配置类中@Import按照导入的顺序加载;
  • 配置类@Bean方法定义的Bean按照方法的声明顺序加载。

如果要人为控制Bean的加载顺序,可以使用@order或@DependsOn注解。

2 三种Bean注入方式

2.1 构造器注入 | Constructor Injection(推荐)

构造器注入是在组件的构造函数中注入所需的依赖,它是在Bean创建时就注入依赖,创建流程如1.2。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class BeanA {
    private final BeanB beanB;
    private final BeanC beanC;

    public BeanA(BeanB beanB, BeanC beanC) {
        this.beanB = beanB;
        this.beanC = beanC;
    }
    // 其他方法...
}

@Component
public class BeanB {
    // 其他方法...
}

@Component
public class BeanC {
    // 其他方法...
}

使用构造器进行依赖注入时,依赖的对象通常会被声明为final,这样当对象创建后,依赖的Bean不会被改变,可以保证类的一致性。

这样注入的优势是能使Bean之间的依赖关系更加清楚,避免了字段注入可能存在的隐式依赖,如果存在问题(比如循环依赖)会在Spring初始化时就抛出异常,而不会等到执行时才出错。

需要注意的是不能显示提供无参构造函数,否则Spring会优先执行无参构造,导致所有依赖的Bean都为null,如果有多个构造函数,选择一个使用@Autowired注解,否则可能报错。

2.2 字段注入 | Field Injection(常用)

字段注入就是使用@Autowired注解自动注入依赖的Bean。它不会在构造函数中注入,而是通过反射在组件构造函数执行后才注入依赖Bean(即Bean实例化完成后才注入依赖项),因此不能使用final修饰依赖Bean,因为使用final字段修饰的变量必须在声明时或在构造函数中初始化,而字段注入在构造函数之后执行。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class BeanA {
	@Autowired
    private BeanB beanB;
}

@Component
public class BeanB {
    // 其他方法...
}

字段注入是开发时最常用的方式,但由于字段注入是在Bean实例后才注入,属于隐式依赖,所以可能会存在空指针问题,而这个问题只有当程序运行时才出现,因此有一定隐患,所以Spring官方更推荐构造器注入。

2.3 方法注入 | Setter Injection

和字段注入类似,只是需要写好一个setter函数,在setter中注入依赖,一个setter方法通常对应一个依赖,@Autowired注解写在setter方法上:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class BeanA {
    private final BeanB beanB;
    private final BeanC beanC;
    
	@Autowired
    public setBeanB(BeanB beanB) {
        this.beanB = beanB;
    }
    
    @Autowired
    public setBeanC(BeanC beanC) {
        this.beanC = beanC;
    }

setter注入的优势是可以灵活注入bean,相比构造器一次性写入更加清晰一些,缺点和字段注入类似。

2.4 三种方式注入顺序

如果一个组件中同时存在以上三种注入方式,执行顺序是?

按照构造器注入–>字段注入–>方法注入的原则执行。

首先执行构造函数,注入在构造函数初始化的Bean。构造函数执行结束后,Spring将处理字段注入,然后在容器中查找并注入依赖Bean。最后如果存在带有@Autowired注解的setter方法,Spring会再调用这些方法注入依赖。

3 循环依赖

循环依赖指的是多个Bean之间互相需要对方作为成员变量,导致依赖链变成了环的状态,如BeanA需要注入BeanB,BeanB需要注入BeanA。

3.1 构造器注入

构造器注入时会通过构造函数注入所有必须的依赖,当两个组件BeanA和BeanB之间存在循坏依赖时,执行BeanA的构造函数需要注入BeanB(此时BeanA还未创建),由于BeanB还未生成,因此转而先创建BeanB,执行BeanB的构造函数,而BeanB同样需要注入BeanA,于是出现了死锁情况,两个Bean都无法创建,因此如果使用构造器注入而又出现循环依赖时,Spring会直接抛出BeanCurrentlyInCreationException异常。

3.2 字段/setter注入

使用字段/setter注入在循环依赖时不会抛出异常(但很容易出问题),主要是通过三级缓存来提前暴露Bean的方式解决的。

一般的Bean需要通过实例化(构造器)、属性填充(注入依赖)、初始化(执行Bean的init方法)才能完成初始化。而在循环依赖的情况下,字段/setter注入会在实例化后先创建当前对象的“代理”或“占位符”实例/引用(半成品实例,但可以被注入到其他Bean中),这个实例可以通过反射等它依赖的对象存在后再进行属性填充,因此不会在创建时出现死锁(没有循环等待),而构造器注入必须注入_完全初始化_的依赖后才能实例化,因此会死锁。

3.2.1 三级缓存实现

三级缓存是解决循环依赖的关键,spring的三级缓存实现在DefaultSingletonBeanRegistry 类中,主要有三个Map,分别是:

  • singletonObjects,一级缓存,用于存放完全初始化完成的单例Bean,可以被其他Bean直接引用
  • earlySingletonObjects,二级缓存,用于存放提前暴露,即未完全初始化的半成品Bean,目的是为了解决循环依赖
  • singletonFactories,三级缓存,用于存放ObjectFactory对象,该对象可以创建半成品Bean放入二级缓存。三级缓存主要用于解决AOP代理对象。
3.2.2 三级缓存的工作原理:

当需要注入某个Bean时,spring通过如下顺序到三级缓存中找:

  1. 检查一级缓存是否存在完全初始化的Bean,若有则返回;
  2. 一级缓存未找到且该Bean正在创建中则继续检查二级缓存,否则返回null。二级缓存保存的是半成品Bean,在循环依赖时才用到,若有也直接返回;
  3. 二级缓存未找到且允许早期依赖则去三级缓存找,否则返回null。如果查询到对象工厂,则会调用工厂的 getObject() 方法生成Bean的早期引用然后将其存入二级缓存,同时将工厂从三级缓存中移除;
  4. 当Bean的生命周期完成后(注入依赖,初始化函数回调),spring会将完全体Bean放入一级缓存,同时移除二三级缓存中的该Bean。
3.2.3 具体例子

以BeanA/B为例:

  1. 当容器尝试创建BeanA时候,发现它依赖BeanB,但此时在缓存中未存在BeanB,因此会先创建BeanA的ObjectFactory对象放入三级缓存中并标记BeanA为正在创建中,然后转而去创建BeanB;
  2. 创建BeanB时,发现其依赖于BeanA,且能够在三级缓存中发现BeanA的工厂对象,那么会使用工厂创建BeanA的半成品对象放入二级缓存,然后清除BeanA在三级缓存中的工厂;
  3. 半成品BeanA返回给BeanB完成注入,打破循环依赖,BeanB继续初始化生成完全体BeanB放入一级缓存,二三级缓存清除BeanB;
  4. BeanB创建后返回BeanA完成注入,A继续初始化生成完全体BeanA放入一级缓存,二三级缓存清除BeanA;
  5. BeanA和BeanB都完成初始化。
3.2.4 为何要第三级缓存ObjectFactory?

在上面的Bean创建流程中可以看到,解决循环依赖时最终还是从二级缓存中找到半成品Bean,那既然如此,为什么在递归创建依赖对象时,不直接先生成当前对象的半成品Bean放入二级缓存,而是先创建当前Bean的工厂对象呢?

这是因为二级缓存只是看似能解决循环依赖,但是存在着以下问题:

  1. 可能创建多余的半成品对象:若没有三级缓存保存工厂对象,那么在创建某Bean并在递归创建依赖Bean之前就应该创建好半成品Bean,以解决可能存在的循环依赖,但是循环依赖并不是一定存在的,这种方式在无循环依赖的情况下会创建很多无用的半成品Bean,因为它们本来都可以正常初始化直接生成完全Bean。
  2. 难以支持代理Bean创建:如果某个类使用了AOP特性(或事物),那么这个类被注入时应该使用它的代理对象。若只使用二级缓存,那么要么生成Bean的原始半成品对象,要么生成Bean的代理半成品对象,但无论是哪种模式都不合适,因为前者无法满足代理需求,后者会使得普通对象也注入代理对象,造成不必要的开销。

正是因为这些问题,spring才采取了三级缓存,工厂对象的引入可以很好解决上面两个问题:

  1. 延迟生成半成品Bean:在三级缓存架构下,首先生成的是对象工厂放入三级缓存,当后续存在循环依赖时才会生成半成品Bean放入二级缓存并被使用。
  2. 支持动态增强(代理),能生成原始对象或代理对象。在Bean的创建过程中,spring会检测该类是否使用了切面或增强(事物注解),如果是则证明需要代理对象,那么在使用objectFactory.getObject()时就会生成代理对象,否则生成原始对象。
3.3 乱想:构造器+字段?

想到了一个组合:如果BeanA使用构造器注入BeanB,而BeanB使用字段注入注入BeanA,那么能否通过占位符(半成品)实例实现注入呢?

答案是不行,原因主要有三点:

  1. 构造器注入要求注入的依赖必须是完全初始化的实例【核心】。
  2. 构造器注入时,在循环依赖情况下被动生成的占位符实例不允许使用(因为构造函数不允许注入未完全实例化的对象,本质上与第二点一样)。
  3. 构造器注入不会像字段注入那样生成占位符实例,因为就算生成了也不完全,无法使用

因此无论是先创建BeanA还是先创建BeanB都会抛出异常。

先创建BeanA:发现依赖BeanB,转而创建BeanB,又发现BeanB依赖BeanA,因此尝试创建BeanA的占位符实例,但是因为A是构造器注入,必须注入BeanB的完整实例(但并不存在),因此不允许使用占位符实例,失败。

先创建BeanB:发现依赖BeanA,转而创建BeanA,BeanA必须使用完全实例化的BeanB,不会创建BeanB的占位符实例,因此无法达成,失败。

3.4 解决方案

一般情况下需要避免循环依赖,如果存在,可以尝试将一些依赖关系移除,重构依赖关系,降低耦合。或者可以使用@Lazy注解延迟Bean的加载,懒加载可以让Bean在被使用时才注入。

@Component
public class BeanA {

    @Autowired
    @Lazy
    private BeanB beanB; // 延迟注入

    // 其他方法...
}

@Component
public class BeanB {

    @Autowired
    private BeanA beanA; // 直接注入

    // 其他方法...
}
构造器注入详解 Spring中依赖数注入的推荐方式,以及为什么使用构造注入时可不用@Autowired 阅读详情

相关推荐

spring 深入了解bean的创建过程

一、创建bean之初 spring调用 beanFactory.preInstantiateSingletons()此方法完成整个bean生产以及依赖注入,那么在生成bean之前,spring做了哪些事呢? 1.盘点bean定义是否是bean工厂 遍历所有beandefinition 非懒加载以及非抽象bean,单例,去执行AbstractBeanFactory.isFactoryBean(beanName) 方法判断是否是重写 SmartFactoryBean接口的isEagerI...

qq_36869100的博客 4328

依赖注入方式field,setter,constructor实现原理剖析

依赖注入方式field,setter,constructor实现原理剖析 目录概述实现思路分析Field 注入Constructor 注入相关工具如下:分析:小结:参考资料和推荐阅读 LD is tigger forever,CG are not brothers forever, throw the pot and shine forever. Modesty is not false, solid is not naive, treacherous but not deceitful, stay w

专注Java(全栈)应用开发,求知若渴,虚心若愚,talk is cheap, show me the code. 737

spring springboot websocket 不能注入( @Autowired ) service bean 报 null 错误

springboot 的 websocket 里面使用 @Autowired 注入 service 或 bean 时,报空指针异常,service 为 null(并不是不能被注入)。 解决方法:将要注入的 service 或 bean 改成 static,在使用时,就不会为null了。 直接上代码: @Controller @ServerEndpoint(value="/chatSocket")...

张圣晨的博客 2万+

Bean的四种注入方式

1.set方法注入 2.构造器注入 3.静态工厂注入 4.实例工厂注入 我使用下面两个类来进行注入的演示,这两个类分别是User和Car类: Car类: public class Car { // 只包含基本数据类型的属性 private int speed; private double price; public Car() { } public Car(int speed, double price) { this.speed

weixin_45907591的博客 2万+

Spring Boot中的依赖注入是如何工作

在 Spring Boot 中,依赖注入的工作原理是通过 Spring 容器管理对象的生命周期,并将所需的依赖注入到类中。常见的注入方式包括构造器注入、字段注入和 setter 注入。Spring 使用@Autowired注解来自动注入依赖,通过@Component和其衍生注解(如@Service等)标记 Bean。还可以通过@Qualifier和@Primary注解来解决多个 Bean 的冲突问题。

有时间就写写代码 1637

半导体工厂自动化实战:用secs4net实现设备与MES系统通信(附完整代码)

本文详细介绍了如何利用secs4net框架实现半导体工厂设备与MES系统的高效通信。通过解析SECS/GEM协议的核心架构、关键业务场景实现及性能优化实践,帮助开发者快速掌握工业自动化通信技术,提升生产效率和系统稳定性。

transformer2023的博客 892

SpringBoot的Bean类三种注入方式(附带LomBok注入)

本文详细介绍了SpringBoot的Bean类三种注入方式,并附上 Lombok 的注入方式。

驴大毛的博客 1688

线性代数——(期末突击)行列式(上)-行列式计算、行列式的性质

简单解释一下:4213原本的顺序应为1234,对于‘4’而言,‘2’、‘1’、‘3’都应该排在它的前面,所以此处记逆序数为3;对于‘2’而言,‘1’应该排在它的前面,而‘3’排在它之后 是合理的,所以此处只有一个逆序数;最后看‘1’,其后面的‘3’排在后面显然也是合理的,故而4213的逆序数为4.一般我们使用这个性质来计算四阶行列式,也就是将其变换成三角行列式,再计算对角线的值;以主对角线为分界线的就为正三角,反之则为反三角行列式。若行列式某一行(列)为0,则该行列式=0.将和的那一行分开,其余行。

li13437542099的博客 1万+

SpringBoot - Bean的实例化和依赖注入方式

在 Spring 中,实例化 Bean 有三种方式,分别是构造器实例化、静态工厂方式实例化和实例工厂方式实例化。可以看到编译报错了,因为String类并不是受Spring容器管理的bean,所以在实例化时无法自动注入String类型的实例。当 OrderService 中存在无参构造函数和带参构造函数时,默认会调用无参构造函数实例化bean;如果bean中存在无参构造器和带参构造器,会调用哪个构造器来实例化bean呢?使用构造器依赖注入的同时默认也会使用该构造器进行bean的实例化。

你今天真好看呀 2242

NX二次开发编译时dll自动数字签名及拷贝

在UG5.0开始,所有基于UG二次开发的DLL都要“签名”后才能被客户端上正版的NX调用。

菜鸟爱飞不飞的博客 2683

CosyVoice 本地部署详细教程 手把手小白教程

本文提供了详细的CosyVoice本地部署教程,强调了避免中文名称和空格的重要性,并列出了必要的软件安装步骤,包括CUDA、cuDNN、Git和Miniconda。教程涵盖了从检查CUDA版本到下载模型和运行模型的全过程,确保用户能够顺利部署并使用CosyVoice。

huazn612的博客 2万+

Spring Boot中Bean的 构造器注入、字段注入和方法注入

注入方式适用场景优点缺点构造器注入依赖关系不可变,且依赖为必需的情况强制依赖、易于测试、不可变性参数较多时不易读,灵活性差字段注入简单、快速的注入,依赖可选或不复杂的情况简单、代码简洁、实现快速不易测试、依赖关系不明确、耦合度高方法注入依赖关系可变,依赖为可选的情况适合依赖可变、Setter可重复调用依赖关系不明确、可能导致空指针异常对于必需依赖,推荐使用构造器注入,因为它强制要求依赖关系的明确性并且不可变。对于可选依赖,或者在需要某种后期注入的情况下,可以使用Setter方法注入。

2301_80190170的博客 1746

FPGA实战:从零构建eMMC控制器(Verilog篇)

本文详细介绍了如何使用Verilog从零构建FPGA上的eMMC控制器,涵盖eMMC接口基础、命令系统解析、关键模块设计及性能优化技巧。通过实战案例,帮助开发者掌握高速数据存储解决方案,提升嵌入式系统开发能力。

weixin_26802933的博客 297

Spring Boot-Bean注入问题

在Spring Boot开发中,Bean注入问题虽然常见,但大多数都可以通过正确的注解配置和理解Spring的依赖注入机制来解决。常见的注入问题包括Bean未找到、循环依赖、多个实现注入等。推荐的做法是使用构造函数注入,它可以避免大多数注入问题,提升代码的可测试性和可维护性。同时,也要注意Bean的生命周期和作用域,确保合适的Bean管理策略。

Flying_Fish_roe的博客 2324

PCIE的MSI中断处理机制与优化策略

PCIe设备的。

xiaoheshang_123的博客 516

TenserRt平台SMOKE 3D目标检测部署完整教程:从理论到实践

本教程详细介绍了在RK3588平台上部署SMOKE 3D目标检测模型的完整流程。SMOKE是一种创新的单阶段单目3D检测方法,通过关键点估计直接预测3D目标信息,有效解决了深度信息缺失等挑战。文章从理论基础出发,解析了SMOKE的核心算法和网络架构,包括DLA-34主干网络和关键点中心化策略。同时提供了详细的Docker环境配置、模型导出到ONNX格式的实践指南,以及TensorRT引擎构建和性能优化的关键技术要点。该教程为开发者在嵌入式平台上实现高效3D目标检测提供了完整的技术参考。

LXY_LOVE36的博客 371

SpringBoot中的bean注入方式和原理介绍

在Spring Boot中,Bean是一个被Spring容器管理的Java对象。当Spring容器启动时,它会读取应用程序的配置文件(如application.properties或application.yml)并创建所有的Bean。开发者可以在配置文件中定义Bean,也可以使用注解的方式定义Bean。定义Bean的方式多种多样,包括XML配置文件、Java配置类、注解等。Spring Boot的Bean是单例的,也就是说,只会创建一个实例,然后在需要的地方共享使用。

Dark_orange的博客 3006

YOLOv8 改进:添加 LSK 注意力机制

通过添加 LSK 注意力机制,YOLOv8 能够更有效地捕捉特征图上的重要信息,提高检测性能,尤其是在复杂场景下展现出色的表现。这种方法不仅适用于资源受限的设备,还能在丰富多样的实际应用中提供强劲支持。

走向CTO的路上... 1221

@Autowired 和 构造器 注入 Bean 有什么区别

构造器注入是更推荐的方式,尤其在注重代码质量、可测试性和可维护性的场景中。@Autowired注解可以作为补充,在特定场景下简化开发流程。在实际开发中,根据项目的复杂度和需求选择合适的注入方式,并遵循良好的设计原则,能够帮助写出更优雅、更健壮的代码。

大一点的小孩 1091

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

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

Spring构造器的三种注入方式

构造器注入:通过构造方法注入就相当于给构造方法的参数传值,构造注入的优势是通过构造强制依赖关系,使得实例化出的bean对象一定是完整的或者可以使用的。 Salary类 public class Salary { private BigDecimal money; private int day; public Salary(){} public Salary(BigDecimal money, int day) { this.money = money;

weixin_43808717的博客 7064

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

【SpringBoot】Bean 是什么?

定义。

yuxiangdeming的博客 1万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

面试官:Spring是如何解决循依赖问题?

从字面上来理解就是 Spring Bean 之间的依赖产生了循环,例如 A 依赖 B ,B 依赖 C,C 依赖 A,如下:@Service@Autowired@Service@Autowired@Service@Autowired。

chenssy 的技术博客 1422
上一篇: Spring Boot 3.4 正式发布,结构化日志!
下一篇: SpringBoot项目如何导入外部jar包:详细指南
AIGC镜像空间
博客等级 码龄5年 4万+粉丝 689原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值