Java外功精要(2)——Spring IoC&DI

Java外功精要(2)——Spring IoC&DI

1.IoC(控制反转)

1.1 Spring Ioc VS Servlet

在上文:Java外功基础(1)——Spring Web MVC中,很形象地模拟出使用Spring"建造房子"的大概流程。使用Spring建造房子不需要像Servlet那样烧制每一块砖,只需要从Spring中取出一个个提前预制好的组件然后组装即可。换言之:Spring是包含了大量工具的IoC容器

在这里插入图片描述

1.2 IoC解析

1.2.1 IoC概述

概念:IoC(Inversion of Control,控制反转),是一种设计原则,用于减少代码间的直接依赖关系。传统编程中,调用者通常主动创建和管理被调用者的生命周期,而 IoC 将这种控制权交给外部容器或框架,由容器负责对象的创建、依赖注入和管理
示例一:传统编程模式

classCar{protectedFramework framework;publicCar(){ framework =newFramework();System.out.println("car init");}publicvoidrun(){System.out.println("car run");}}classFramework{protectedBottom bottom;publicFramework(){ bottom =newBottom();System.out.println("framework init");}}classBottom{protectedTire tire;publicBottom(){ tire =newTire();System.out.println("bottom init");}}classTire{publicTire(){System.out.println("tire init");}}publicclassMain{publicstaticvoidmain(String[] args){Car car =newCar(); car.run();}}
缺点:所有依赖都在类内部硬编码,缺乏灵活性难以修改组件的具体实现(例如更换Tire的类型或参数)组件之间耦合度高

示例二:IoC

classCar{protectedFramework framework;publicCar(Framework framework){this.framework = framework;System.out.println("car init");}publicvoidrun(){System.out.println("car run");}}classFramework{protectedBottom bottom;publicFramework(Bottom bottom){this.bottom = bottom;System.out.println("framework init");}}classBottom{protectedTire tire;publicBottom(Tire tire){this.tire = tire;System.out.println("bottom init");}}classTire{protectedint size;protectedString color;publicTire(int size,String color){this.size = size;this.color = color;System.out.println("tire init");}}publicclassMain{//main方法中实例化并保存了多个对象,理论上可以视为一种简单的容器实现publicstaticvoidmain(String[] args){Tire tire =newTire(10,"blue");Bottom bottom =newBottom(tire);Framework framework =newFramework(bottom);Car car =newCar(framework); car.run();}}
优点:依赖通过构造函数从外部注入(依赖注入),组件之间解耦可以灵活定制组件的具体实现(例如Tire的size和color可动态配置)

1.2.2 IoC容器管理

Spring IoC容器保存了以下几类核心内容:Bean定义(Bean Definitions):这是容器保存的最核心的元数据。它就像是对象的“蓝图”或“配方”,告诉容器如何创建一个Bean。容器在启动时(比如ApplicationContext被刷新时)会加载并解析这些定义Bean实例(Bean Instances):Bean定义创建出来的实际对象Bean之间的依赖关系(Dependencies):IoC的核心是“控制反转”,即由容器来注入依赖。因此,容器内部维护着一个依赖关系图Bean生命周期(Lifecycle State):管理Bean的整个生命周期已创建/未创建依赖注入是否完成初始化方法是否已执行是否已被销毁

1.3 ApplicationContext

定义:ApplicationContext是Spring IoC容器的核心接口,并有多种实现类。它实现了BeanFactory接口,因此可以通过getBean()方法获取Bean实例,但在实际开发中应优先使用依赖注入
//标识该类为Spring项目的启动类@SpringBootApplicationpublicclassSpringIocApplication{publicstaticvoidmain(String[] args){ApplicationContext context =SpringApplication.run(SpringIocApplication.class, args);}}

1.4 类注解

在Spring中有五大类注解,主要用于类级别的声明。它们都源自 @Component,它们在功能上几乎一致,主要区别在于语义和用途,用于标识不同架构层次的组件,让代码结构更清晰@Component - 组件:最基础的通用注解,用于标记任何一个需要被Spring管理的组件,当你不确定一个类属于@Controller、@Service、@Repository中的哪一类时,或者它就是一个通用的工具类、管理器等,就可以使用它@Controller - 控制器:专门用于标记 MVC 模式中的控制器,用于接收 Web 请求、处理业务逻辑并返回视图或数据派生注解:@RestController(@Controller + @ResponseBody)@Service - 业务逻辑层:专门用于标记业务逻辑层的组件。它本身不提供额外功能,但通过这个名称,开发者可以清晰地知道这个类包含了核心业务规则@Repository - 数据访问层:专门用于标记数据访问层的组件,用于封装对数据库等数据源进行增删改查的类特殊功能:自动将平台特定的异常(如SQLException)转换为Spring统一的DataAccessException层次结构中的非受查异常统一异常体系提供更有意义的异常信息,如BadSqlGrammarException(SQL语法错误)简化异常处理,由于转换后的异常都是非受查异常,不再需要写大量的try-catch块,可以选择在适当的层次统一处理@Configuration - 配置类:用于标记配置类,其内部可以定义Bean(通常使用@Bean注解)特殊功能:它确保了其中使用@Bean注解的方法的单例性。Spring 会通过CGLIB代理来拦截对@Bean方法的调用,确保每次返回的是同一个实例(单例作用域下)

1.5 获取Bean

1.5.1 通过Bean的类型获取

//将HelloController类交给Spring管理@ControllerpublicclassHelloController{publicvoiddemo(){System.out.println("Hello HelloController");}}
@SpringBootApplicationpublicclassSpringIocApplication{publicstaticvoidmain(String[] args){ApplicationContext context =SpringApplication.run(SpringIocApplication.class, args);//通过Bean的类型获取HelloController helloController = context.getBean(HelloController.class); helloController.demo();}}

如果HelloController类没有交给Spring管理,会抛出:

在这里插入图片描述


如果某接口(类)有多个实现类,此时根据类型来获取Bean会抛出:

publicinterfaceFunc{}@Service("dataBaseFunc")//设置Bean的名称为dataBaseFuncclassDataBaseFuncimplementsFunc{}@Service("fileFunc")//设置Bean的名称为fileFuncclassFileFuncimplementsFunc{}
在这里插入图片描述

1.5.2 通过Bean的名称(ID)获取

在Java中,Bean的命名规范如下:
Bean命名约定
约定是在命名bean时使用标准的Java约定作为实例字段名。也就是说,bean名称以小写字母开头,然后使用驼峰式大小写。此类名称的示例包括accountManager,accountService,userDao,loginController

以JDK17为例,在java.beans.Introspector类中提供了如下方法用于Bean的命名

publicstaticStringdecapitalize(String name){if(name ==null|| name.length()==0){return name;}//如果类名的前两个字母都是大写,那么Bean的名字就是类名if(name.length()>1&&Character.isUpperCase(name.charAt(1))&&Character.isUpperCase(name.charAt(0))){return name;}char[] chars = name.toCharArray();//将类名的第一个字母转为小写作为Bean的名称 chars[0]=Character.toLowerCase(chars[0]);returnnewString(chars);}

示例1:

publicinterfaceFunc{voidinit();}@Service("dataBaseFunc")//设置Bean的名称为dataBaseFuncclassDataBaseFuncimplementsFunc{@Overridepublicvoidinit(){System.out.println("database init");}}@Service("fileFunc")//设置Bean的名称为fileFuncclassFileFuncimplementsFunc{@Overridepublicvoidinit(){System.out.println("file init");}}
@SpringBootApplicationpublicclassSpringIocApplication{publicstaticvoidmain(String[] args){ApplicationContext context =SpringApplication.run(SpringIocApplication.class, args);Func dataBaseFunc =(Func)context.getBean("dataBaseFunc");Func fileFunc =(Func)context.getBean("fileFunc"); dataBaseFunc.init(); fileFunc.init();}}
运行结果
database init
file init

示例2:以上述HelloController为例

@SpringBootApplicationpublicclassSpringIocApplication{publicstaticvoidmain(String[] args){ApplicationContext context =SpringApplication.run(SpringIocApplication.class, args);HelloController helloController =(HelloController)context.getBean("helloController");}}
运行结果
Hello HelloController

1.6 方法注解 - @Bean

1.6.1 特性解析

作用:在五大类注解标记的类的方法上使用,告诉Spring该方法返回的对象应该被注册为Bean
使用场景:配置类中定义第三方库的Bean或需要复杂初始化逻辑的Bean
packageorg.example.springioc.model;@DatapublicclassUserObject{privateString name;privateInteger age;privateInteger id;publicUserObject(){}publicUserObject(String name){this.name = name;}publicUserObject(String name,Integer age){this.name = name;this.age = age;}publicUserObject(String name,Integer age,Integer id){this.name = name;this.age = age;this.id = id;}}packageorg.example.springioc.configuration;@ConfigurationpublicclassUserConfiguration{@BeanpublicUserObjectgetUserObject1(){//你完全控制对象的创建过程returnnewUserObject();//无参构造}@BeanpublicUserObjectgetUserObject2(){//你可以传递任意参数returnnewUserObject("李四");//带参构造}}
优点:完全控制对象创建,可以传递参数、调用方法、进行复杂初始化
@Component//或其他四大注解publicclassUserObject{privateString name;privateInteger age;//Spring只会调用无参构造方法publicUserObject(){//Spring通过反射创建对象时,只会调用这个构造方法//你无法传递"张三",18这样的参数}publicUserObject(String name,int age){this.name = name;this.age = age;}}
问题:Spring通过反射创建Bean时,默认调用无参构造方法,你无法传递特定参数

1.6.2 通过Bean的类型获取

与五大类注解一致

1.6.3 通过Bean的名称(ID)获取

与五大注解不同,使用@Bean标注方法时方法名就是该Bean的名称
@SpringBootApplicationpublicclassSpringIocApplication{publicstaticvoidmain(String[] args){ApplicationContext context =SpringApplication.run(SpringIocApplication.class, args);UserObject getUserObject1 =(UserObject)context.getBean("getUserObject1");System.out.println(getUserObject1);UserObject getUserObject2 =(UserObject)context.getBean("getUserObject2");System.out.println(getUserObject2);}}
运行结果
UserObject(name=null, age=null, id=null)
UserObject(name=李四, age=null, id=null)

1.7 @ComponentScan - 扫描路径

概念:@ComponentScan是Spring框架中一个非常核心的注解,它负责告诉Spring容器去哪里扫描那些被@Component、@Service、@Repository、@Controller等注解标记的类,并将它们自动注册为Bean如果一个类没有添加Spring的五大注解,那么即使它位于扫描路径下,它也不会被注册为Spring容器中的Bean

在启动类中,@SpringBootApplication注解包含了@ComponentScan注解,默认扫描路径是启动类所在的包及其子包(可以显式配置来指定扫描路径,如@ComponentScan(basePackages = {“org.example.springioc”}))

在这里插入图片描述

2.DI(依赖注入)

2.1 概述

依赖注入是一种设计模式,它将对象的依赖关系(即它所需要的其他对象)从外部注入,而不是由对象自己在内部创建

2.2 构造方法注入(Constructor Injection)

@ControllerpublicclassHelloController{privateHelloService helloService;privateHelloComponent helloComponent;//如果只有一个构造方法,只能使用该构造方法//当存在多个构造方法时,如果有无参构造方法,默认调用无参构造方法//当存在多个构造方法时,如果没有无参构造方法,Spring就不知道该用哪个构造方法,需要使用@Autowired指定一个默认的构造方法publicHelloController(){}publicHelloController(HelloService helloService){this.helloService = helloService;}@AutowiredpublicHelloController(HelloService helloService,HelloComponent helloComponent){this.helloService = helloService;this.helloComponent = helloComponent;}publicvoiddemo(){ helloService.demo(); helloComponent.demo();System.out.println("Hello HelloController");}}
构造方法使用规范:当添加有参构造方法时,显式添加无参构造方法如果存在多个构造方法,使用@Autowired指定一个默认的构造方法

2.3 Setter方法注入(Setter Injection)

@ControllerpublicclassHelloController{privateHelloService helloService;privateHelloComponent helloComponent;//搭配@Autowired使用@AutowiredpublicvoidsetHelloService(HelloService helloService){this.helloService = helloService;}@AutowiredpublicvoidsetHelloComponent(HelloComponent helloComponent){this.helloComponent = helloComponent;}publicvoiddemo(){ helloService.demo(); helloComponent.demo();System.out.println("Hello HelloController");}}

2.4 字段/属性注入(Field Injection)

@ControllerpublicclassHelloController{@AutowiredprivateHelloService helloService;@AutowiredprivateHelloComponent helloComponent;publicvoiddemo(){ helloService.demo(); helloComponent.demo();System.out.println("Hello HelloController");}}

默认行为:按类型匹配(byType)

  • 查找候选Bean:Spring会首先在IoC容器中查找类型匹配的Bean
  • 判断并注入
    • 找到0个:如果required属性为true(默认),则会抛出NoSuchBeanDefinitionException异常
    • 找到1个:直接注入,这是最理想的情况
    • 找到多个:此时按类型匹配失败,Spring 会尝试后备策略,即按名称匹配 (byName)。它会将变量名(或属性名)作为Bean的ID去容器中查找

2.5 优缺点对比

构造方法注入:优点:可以注入final修饰的属性注入的依赖在调用前一定会完全初始化,因为构造方法在类加载阶段执行在Spring以外的其他框架中同样支持,构造方法由JDK提供缺点:注入多个依赖时代码量庞大Setter方法注入:优点:Setter方法可以被多次调用,这意味着该依赖可以多次注入缺点:不能注入final修饰的属性多次注入可能导致依赖被修改字段/属性注入:优点:代码简洁,使用方便缺点:不能注入final修饰的属性在非IoC容器中不可用

2.6 候选Bean问题

在使用@Autowired注入时,优先按照类型匹配,如果匹配到多个Bean,会将变量名(或属性名)作为Bean的ID去容器中查找。当变量名(或属性名)匹配失败时,程序无法运行成功
在上述代码中,UserController类需要注入一个单例Bean,却发现多个候选Bean,这叫做候选Bean问题

2.6.1 @Primary注解

作用:指定当存在多个相同类型的 Bean 时,优先使用被标记的Bean

运行结果:UserObject(name=李四, age=null, id=null)

2.6.2 @Qualifier注解

作用:是Spring框架中用于精确指定要注入哪个Bean的注解,它解决了当存在多个相同类型Bean时的依赖注入歧义问题
运行结果:UserObject(name=王五, age=18, id=102)

2.6.3 @Resource注解

作用:@Resource注解是Java标准注解,Spring框架提供了对它的支持。它是@Autowired的一个替代方案,但在匹配机制上有重要区别

也可以明确指定名称,按名称精确匹配

在这里插入图片描述

优先按照Bean的名称匹配

在这里插入图片描述

2.6.4 优先级

当@Primary、@Qualifier、@Resource、@Autowired同时存在时,优先级如下: Resource > Qualifier > Primary > Autowired

Read more

【AI辅助编程】【Claude Code】----秒杀 Cursor!Claude Code 保姆级教程,从安装到实战全过程,一篇文章给你透

【AI辅助编程】【Claude Code】----秒杀 Cursor!Claude Code 保姆级教程,从安装到实战全过程,一篇文章给你透

文章目录 * 前言 * 一、基础概念解析, * 1.1、什么是Claude Code? * 1.2、Claude Code能干嘛? * 二、安装 Claude Code * 2.1、(方式一)基于node.js环境 * 2.2、(方式二)不依赖node.js环境,原生版(推荐) * 三、配置 * 3.1配置大模型端点和密钥 * 1.注册账号 (通过上面提供的连接注册) * 2.获取API Key * 3.配置cluade code 环境变量 * 4.测试配置: * 5.切换模型(非必要,可跳过) * 6.查看token用量

By Ne0inhk
相干伊辛机在医疗领域及医疗AI领域的应用前景分析

相干伊辛机在医疗领域及医疗AI领域的应用前景分析

引言:当量子退火遇见精准医疗 21世纪的医疗健康领域正经历着一场由数据驱动的深刻变革。从基因组学到医学影像,从电子病历到可穿戴设备,医疗数据正以指数级增长。然而,海量数据的背后是经典的“组合爆炸”难题——例如,药物分子中电子的量子态搜索、多模态医疗影像的特征匹配、个性化治疗方案的组合优化等,这些问题对经典计算机,甚至对传统的超级计算机而言,都构成了难以逾越的计算壁垒。 相干伊辛机(Coherent Ising Machine, CIM)作为一种基于量子光学和量子退火原理的新型计算范式,为解决这类组合优化问题提供了全新的物理路径。它不同于通用量子计算机(如超导门模型),CIM是专为寻找复杂伊辛模型基态而设计的专用量子处理器。本文将深入探讨CIM如何凭借其强大的并行搜索能力,在药物研发、精准诊断、个性化治疗以及医疗AI优化等领域,从计算底层赋能医疗科技的未来。 一、 相干伊辛机:从统计物理到量子计算引擎 要理解CIM在医疗领域的潜力,首先需要深入其物理内核,厘清它如何通过光的相干性来高效解决现实世界的复杂问题。 1. 伊辛模型:组合优化的“通用语言” 伊辛模型最初源于统计物理学

By Ne0inhk
多模态检索新突破!Qwen3-VL-Embedding/Reranker AI 真正“看懂“你在搜什么,从图片到视频全拿下!

多模态检索新突破!Qwen3-VL-Embedding/Reranker AI 真正“看懂“你在搜什么,从图片到视频全拿下!

Qwen3-VL-Embedding 和 Qwen3-VL-Reranker:统一多模态表征与排序 摘要 2025年6月,Qwen 团队开源了面向文本的 Qwen3-Embedding 和 Qwen3-ReRanker 模型系列,在多语言文本检索、聚类和分类等多项下游任务中取得了业界领先的性能。 2026年1月,该团队推出了 Qwen 家族的最新成员:Qwen3-VL-Embedding 和 Qwen3-VL-Reranker 模型系列。这些模型基于开源的 Qwen3-VL 模型构建,专为多模态信息检索和跨模态理解场景设计,能够将文本、图像、文档图像和视频等多种模态映射到统一的表示空间中。 Qwen3-VL-Embedding 模型采用多阶段训练范式,从大规模对比预训练逐步发展到重排序模型蒸馏,以生成语义丰富的高维向量。该模型支持 Matryoshka 表示学习(MRL),可灵活选择嵌入维度,并能处理最多 32K tokens 的输入。作为补充,Qwen3-VL-Reranker 采用交叉编码器架构和交叉注意力机制,对查询-文档对进行细粒度的相关性评估。 两个模型系列继承了

By Ne0inhk
【OpenClaw企业级智能体实战】第01篇:从零搭建你的第一个AI员工(原理+算法+完整代码+避坑指南)

【OpenClaw企业级智能体实战】第01篇:从零搭建你的第一个AI员工(原理+算法+完整代码+避坑指南)

摘要:随着AI从“对话时代”迈入“执行时代”,OpenClaw作为开源智能体框架,正在重塑人机协作模式——它不再是被动响应的工具,而是能主动执行任务的“AI员工”。本文基于真实技术原理与实操场景,从背景概念切入,拆解OpenClaw“感知-决策-执行”的核心逻辑,详解算法组件构建思路,并提供从零到一的完整实操流程(含可直接运行的Python代码)。内容兼顾新手入门与进阶提升,强调安全隔离部署原则,避开技术术语堆砌,聚焦实用价值。读者可通过本文掌握OpenClaw基础部署、自定义技能开发、记忆模块集成等核心能力,快速落地自动化办公、信息整理等实际场景,真正体验“低成本、高效率”的AI生产力革命。全文严格遵循真实性原则,无捏造案例与夸大描述,所有代码均经过实测验证。 优质专栏欢迎订阅! 【OpenClaw从入门到精通】【DeepSeek深度应用】【Python高阶开发:AI自动化与数据工程实战】 【YOLOv11工业级实战】【机器视觉:C# + HALCON】【大模型微调实战:平民级微调技术全解】 【人工智能之深度学习】【AI 赋能:Python 人工智能应用实战】

By Ne0inhk