Springboot - 2.控制反转(IoC)和 依赖注入(DI)
✍1.控制反转IoC和依赖注入DI控制反转IoC把对象的实例化、组装等价于“依赖注入”也称“装配”、销毁交给 IOC 容器。依赖注入DIIoC 容器自动将一个 Bean 所需的其他 Bean 注入进来从而解耦组件依赖。按类型注入Autowired按名称注入Resource集合注入List、Set、Map容器自动注入所有匹配 Bean也可使用策略模式优化配置注入Value单值、ConfigurationProperties结构化对象框架以默认开启Configuration是配置类声明注解不参与注入。方式注解/用法适用场景特点单值注入Value(${key:default})或Value(#{...})简单、零散配置如端口、开关✅ 轻量⚠️ 无类型安全、不支持集合/嵌套、无校验类型安全批量注入ConfigurationProperties(prefixxxx)Component多配置项、结构化List/Map/嵌套、需校验或 IDE 提示✅ 松散绑定、JSR-303 校验如NotBlank、元数据支持⚠️ 需启用Spring Boot 2.2 推荐ConfigurationPropertiesScan配置类中动态注入ConfigurationBean方法参数ValueBean 构造需结合配置与逻辑如超时创建服务✅ 灵活可控适合非属性类对象初始化禁止混用同一配置项同时用ConfigurationProperties和Value—❌ 导致重复管理、语义不清、维护困难 →统一用ConfigurationProperties管理结构化配置1.定义Bean在Spring Boot中您可以使用Component及其衍生注解如Service、Repository、Controller等来定义Bean。这些注解标记了一个类作为Spring容器中的一个Bean。例如ServicepublicclassMyService{// ...}2.依赖注入Spring Boot通过IOC容器来实现依赖注入。您可以使用Autowired注解将依赖对象注入到需要它们的地方。例如在构造函数、Setter方法、字段上使用Autowired注解ServicepublicclassMyService{privatefinalAnotherServiceanotherService;AutowiredpublicMyService(AnotherServiceanotherService){this.anotherServiceanotherService;}// ...}3.配置注入Spring Boot推荐使用Java配置类来配置Bean而不是XML配置文件。您可以使用Configuration注解标记配置类并在方法上使用Bean注解来定义Bean。例如在Spring Boot中配置类是一种使用Java代码来配置应用程序的方式取代了传统的XML配置文件。配置类使用Configuration注解进行标记通常使用Bean注解来定义Bean以及其他配置相关的注解来实现各种功能。以下是关于配置类在Spring Boot中的详细解释和示例创建配置类首先您需要创建一个Java类并使用Configuration注解来标记它使其成为一个配置类。importorg.springframework.context.annotation.Configuration;ConfigurationpublicclassAppConfig{// Configuration related methods will be defined here}定义Bean在配置类中您可以使用Bean注解来定义Bean。方法的返回值类型将成为该Bean的类型方法名将成为该Bean的名称。importorg.springframework.context.annotation.Bean;ConfigurationpublicclassAppConfig{BeanpublicMyServicemyService(){returnnewMyService();}}依赖注入其他Bean在配置类中您可以使用Autowired注解来依赖注入其他Bean就像在其他普通的组件类中一样。importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;ConfigurationpublicclassAppConfig{AutowiredprivateAnotherServiceanotherService;BeanpublicMyServicemyService(){returnnewMyService(anotherService);}}使用外部属性配置类还可以使用Value注解来注入外部属性值或者使用ConfigurationProperties注解来绑定属性配置。importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.stereotype.Component;ComponentConfigurationProperties(prefixapp.config)publicclassAppConfigProperties{privateStringgreetingMessage;privateintmaxRetry;privateinttimeout;// Getter and setter methods for the properties}importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.context.ConfigurableApplicationContext;SpringBootApplicationpublicclassApplication{AutowiredprivateAppConfigPropertiesappConfig;publicstaticvoidmain(String[]args){ConfigurableApplicationContextcontextSpringApplication.run(Application.class,args);Applicationapplicationcontext.getBean(Application.class);application.printConfig();}publicvoidprintConfig(){System.out.println(Greeting message: appConfig.getGreetingMessage());System.out.println(Max retry: appConfig.getMaxRetry());System.out.println(Timeout: appConfig.getTimeout());}}组合配置类多个配置类可以组合在一起形成一个综合的配置。Spring Boot会自动将这些配置类合并成一个应用程序上下文。ConfigurationpublicclassDatabaseConfig{// Define database-related beans and configurations}ConfigurationpublicclassMessagingConfig{// Define messaging-related beans and configurations}ConfigurationImport({DatabaseConfig.class,MessagingConfig.class})publicclassAppConfig{// Main configuration and other beans}importorg.springframework.context.annotation.AnnotationConfigApplicationContext;publicclassMainApp{publicstaticvoidmain(String[]args){AnnotationConfigApplicationContextcontextnewAnnotationConfigApplicationContext(AppConfig.class);// Get and use beans from the application context}}总结组合配置类是一种将多个配置类组合在一起的方法使配置更加清晰、模块化和可维护。通过创建主配置类并使用Import注解来导入其他配置类您可以在应用程序中有效地管理配置。这种方法有助于降低配置的复杂性并提高了应用程序的可扩展性和可维护性。4.属性注入除了构造函数和Setter方法注入外您还可以使用Autowired注解在属性上进行依赖注入。这样Spring Boot会自动将依赖注入到属性中。ServicepublicclassMyService{AutowiredprivateAnotherServiceanotherService;// ...}5.Qualifiers和Primary如果存在多个实现相同接口的Bean您可以使用Qualifier注解指定要注入的具体Bean。另外您还可以使用Primary注解标记一个主要的Bean它将被首选用于注入。当您在Spring Boot中使用依赖注入时可能会遇到多个相同类型的Bean的情况例如有多个实现了相同接口的类。在这种情况下为了告诉Spring容器应该注入哪个具体的Bean您可以使用Qualifier注解和Primary注解。Qualifier 注解Qualifier注解用于在存在多个相同类型的Bean时明确指定要注入的Bean的名称。通过指定Qualifier的值您可以告诉Spring容器应该注入哪个具体的Bean。示例ServicepublicclassMyService{privatefinalAnotherServiceprimaryAnotherService;privatefinalAnotherServicesecondaryAnotherService;AutowiredpublicMyService(Qualifier(primary)AnotherServiceprimaryAnotherService,Qualifier(secondary)AnotherServicesecondaryAnotherService){this.primaryAnotherServiceprimaryAnotherService;this.secondaryAnotherServicesecondaryAnotherService;}// ...}Primary 注解Primary注解用于标记一个Bean为首选的Bean当存在多个相同类型的Bean时被标记为Primary的Bean将会被优先注入。如果没有指定Qualifier那么Primary注解的Bean将作为默认选择。示例ServicePrimarypublicclassPrimaryAnotherServiceimplementsAnotherService{// ...}ServicepublicclassSecondaryAnotherServiceimplementsAnotherService{// ...}ServicepublicclassMyService{privatefinalAnotherServiceanotherService;AutowiredpublicMyService(AnotherServiceanotherService){this.anotherServiceanotherService;}// ...}总结在Spring Boot中当存在多个相同类型的Bean时您可以使用Qualifier注解来指定要注入的具体Bean。另外您还可以使用Primary注解来标记一个Bean为首选Bean优先注入。这些注解有助于在多个候选Bean之间进行选择从而满足您的依赖注入需求。6.可选依赖如果依赖对象可能不存在您可以使用Autowired(required false)来标记注入的依赖为可选的。如果找不到匹配的Bean注入的字段将为null。ServicepublicclassMyService{Autowired(requiredfalse)privateAnotherServiceoptionalAnotherService;// ...}7.属性值注入Spring Boot还支持将属性值注入到Bean中您可以使用Value注解来实现。这在配置文件中配置的属性值会注入到Bean的字段或方法参数中。属性值注入是一种在Spring Boot中将外部属性值注入到Bean中的机制。这样您可以将配置信息从代码中分离出来使您的应用程序更加灵活和可配置。Spring Boot通过Value注解来实现属性值注入。以下是属性值注入在Spring Boot中的详细解释和示例在配置文件中定义属性值首先在application.properties或application.yml配置文件中定义属性值。例如在application.properties文件中app.greeting.messageHello from properties file!在Bean中使用 Value 注解然后您可以在Bean的字段、构造函数参数、方法参数等地方使用Value注解来注入属性值。注解的值是从配置文件中读取的属性的名称。示例ServicepublicclassMyService{Value(${app.greeting.message})privateStringgreetingMessage;publicvoidprintGreeting(){System.out.println(greetingMessage);}}使用 SpEL 表达式Value注解还支持使用Spring表达式语言SpEL来计算属性值。您可以在注解中使用${expression}来引用SpEL表达式。示例ServicepublicclassMyService{Value(#{T(java.lang.Math).random()})privatedoublerandomNumber;publicvoidprintRandomNumber(){System.out.println(randomNumber);}}默认值如果属性在配置文件中不存在您可以使用Value注解的defaultValue属性来设置默认值。示例ServicepublicclassMyService{Value(${app.nonexistent.property:Default Value})privateStringdefaultValue;publicvoidprintDefaultValue(){System.out.println(defaultValue);}}总结属性值注入是Spring Boot中的一个重要特性通过使用Value注解您可以将外部属性值注入到Bean中从而使您的应用程序更具灵活性和可配置性。您可以从配置文件中读取属性值并使用SpEL表达式进行计算。另外您还可以设置默认值以防属性在配置文件中不存在。8.集合注入如果需要注入多个相同类型的依赖您可以使用List、Set、Map等集合来进行集合注入。在Spring Boot中集合注入是一种将多个相同类型的依赖对象注入到一个集合中的机制。这种机制非常适用于场景其中您需要处理多个实现了相同接口或父类的依赖对象。Spring Boot通过使用Autowired注解结合List、Set、Map等集合类型使集合注入变得非常方便。以下是集合注入在Spring Boot中的详细解释和示例定义多个实现类首先假设您有多个实现了同一个接口的类例如publicinterfacePlugin{voidexecute();}ServicepublicclassPluginAimplementsPlugin{// ...}ServicepublicclassPluginBimplementsPlugin{// ...}在Bean中使用集合注入然后您可以在需要依赖注入这些实现类的Bean中使用Autowired注解结合集合类型如ListPlugin、SetPlugin、MapString, Plugin等进行集合注入。示例ServicepublicclassPluginManager{privatefinalListPluginplugins;AutowiredpublicPluginManager(ListPluginplugins){this.pluginsplugins;}publicvoidexecuteAllPlugins(){for(Pluginplugin:plugins){plugin.execute();}}}在上面的示例中PluginManager类通过构造函数注入了一个ListPlugin集合该集合包含了所有实现了Plugin接口的Bean。集合注入是Spring Boot中的一个强大特性它允许您将多个相同类型的依赖对象注入到一个集合中使您能够方便地处理多个实现了相同接口或父类的依赖。通过使用Autowired注解和集合类型您可以在Bean中轻松地实现集合注入从而更好地管理和处理依赖关系。总结在Spring Boot应用程序中依赖注入是一种重要的设计模式通过使用Autowired、Qualifier、Value等注解您可以实现将依赖关系从代码中解耦从而使代码更具可维护性和可扩展性。结合Spring Boot的自动配置功能依赖注入可以更加便捷地实现使您能够更专注于业务逻辑的开发。