IOC配置方式
xml 配置
1. 构造器注入(Constructor Injection)
构造器注入通过构造函数将依赖关系传递给目标对象。这种方式确保了依赖项在对象创建时即被提供,因此特别适合于那些依赖项是必须的场景。构造器注入也有助于确保对象的不可变性。
示例:
@Component
public class MyService {
private final MyRepository repository;
@Autowired
public MyService(MyRepository repository) {
this.repository = repository;
}
// Other methods
}
在上面的例子中,@Autowired
注解指示 Spring 通过构造器注入 MyRepository
对象。
2. Setter 注入(Setter Injection)
Setter 注入通过 setter 方法将依赖关系注入目标对象。这种方式适用于可选的依赖项,或者依赖项可以在对象创建后进行修改的场景。
示例:
@Component
public class MyService {
private MyRepository repository;
@Autowired
public void setRepository(MyRepository repository) {
this.repository = repository;
}
// Other methods
}
在这个例子中,@Autowired
注解指示 Spring 通过 setter 方法注入 MyRepository
对象。
3. 字段注入(Field Injection)
字段注入直接将依赖关系注入到目标对象的字段中。这种方式非常简洁,但通常不推荐,因为它使得对象的依赖关系不够明确,并且不利于单元测试。
示例:
@Component
public class MyService {
@Autowired
private MyRepository repository;
// Other methods
}
在这个例子中,@Autowired
注解指示 Spring 直接将 MyRepository
对象注入到 repository
字段中。
4. 方法注入(Method Injection)
方法注入通过将依赖项传递给目标对象中的某个方法来实现。这种方式比较少见,但在某些场景中(例如,依赖项的创建在特定的方法调用时才需要)可能会有用。
示例:
java复制代码
public class MyService {
private MyRepository repository;
@Autowired
public void injectRepository(MyRepository repository) {
this.repository = repository;
}
// Other methods
}
在这个例子中,@Autowired
注解指示 Spring 调用 injectRepository
方法将 MyRepository
对象注入到 MyService
中。
5. 构造器注入(Constructor Injection)的变体(基于 @Value 注解)
除了使用 @Autowired
注解来进行构造器注入外,还可以使用 @Value
注解来注入简单的值,例如配置文件中的值。
示例:
@Component
public class MyService {
private final String appName;
@Autowired
public MyService(@Value("${app.name}") String appName) {
this.appName = appName;
}
// Other methods
}
在这个例子中,@Value("${app.name}")
用于将配置文件中的 app.name
属性值注入到 appName
字段中。
6. 注入集合(Collection Injection)
Spring 还支持将集合类型的依赖项注入到目标对象中,这对于需要动态管理一组对象的场景非常有用。
示例:
@Component
public class MyService {
private final List<MyRepository> repositories;
@Autowired
public MyService(List<MyRepository> repositories) {
this.repositories = repositories;
}
// Other methods
}
在这个例子中,repositories
是一个 List
,Spring 会自动注入所有 MyRepository
类型的 Bean 到这个列表中。
IOC常用注解
@Autowired
@Autowired
注解可以应用于构造方法、setter 方法、字段和方法参数。以下是每种用法的示例:
1. 构造方法注入
构造方法注入是通过构造方法将依赖项注入到 Bean 中。这是推荐的注入方式,特别是当依赖项是必需的时,因为它可以确保依赖项在 Bean 创建时已经被注入。
@Component
public class MyService {
private final MyRepository repository;
@Autowired
public MyService(MyRepository repository) {
this.repository = repository;
}
// Other methods
}
在这个例子中,@Autowired
注解标记了构造方法,Spring 会自动注入 MyRepository
的实例。
2. Setter 方法注入
Setter 方法注入是通过 setter 方法将依赖项注入到 Bean 中。这种方式适用于可选的依赖项,或者依赖项可能在 Bean 创建之后发生变化的场景。
@Component
public class MyService {
private MyRepository repository;
@Autowired
public void setRepository(MyRepository repository) {
this.repository = repository;
}
// Other methods
}
在这个例子中,@Autowired
注解标记了 setter 方法,Spring 会自动注入 MyRepository
的实例。
3. 字段注入
字段注入是直接将依赖项注入到 Bean 的字段中。这种方式简洁,但一般不推荐,因为它使得对象的依赖关系不够明确,并且不利于单元测试。
@Component
public class MyService {
@Autowired
private MyRepository repository;
// Other methods
}
在这个例子中,@Autowired
注解标记了字段,Spring 会自动注入 MyRepository
的实例。
4. 方法参数注入
方法参数注入是将依赖项作为方法参数传递给 Bean 的方法。虽然这种方式较少用,但在某些场景下可能会有用。
@Component
public class MyService {
private MyRepository repository;
@Autowired
public void configure(MyRepository repository) {
this.repository = repository;
}
// Other methods
}
在这个例子中,@Autowired
注解标记了方法参数,Spring 会自动注入 MyRepository
的实例。
处理流程
扫描和解析注解:
-
Spring 容器在启动时,会扫描指定的包路径下的类,查找带有
@Autowired
注解的字段、构造函数或方法。 -
Spring 使用反射技术来获取这些注解的元数据(如注解的类型、位置、修饰的元素等)。
依赖注入逻辑:
-
对于标记了
@Autowired
注解的字段、构造函数或方法,Spring 会尝试根据类型在容器中查找合适的 bean 实例。 -
如果找到唯一的匹配 bean,Spring 会将其注入到标记了
@Autowired
的位置。 -
如果有多个匹配的 bean,Spring 会尝试根据 bean 名称或其他限定符(如
@Qualifier
注解)来进一步筛选。如果仍然不能确定唯一的 bean,Spring 会抛出异常。
处理构造函数注入:
-
如果
@Autowired
应用于构造函数,并且类只有一个构造函数,则 Spring 会自动使用该构造函数进行注入,即使没有明确标注@Autowired
。 -
Spring 会自动解析构造函数的参数类型,并在容器中查找匹配的 bean 进行注入。
处理方法和字段注入:
-
对于方法,Spring 会调用该方法,并传入匹配的 bean 实例作为参数。
-
对于字段,Spring 会通过反射直接设置字段的值。
-
在 Spring Boot 项目中,
@Resource
注解用于依赖注入。它是 Java 自带的标准注解,属于javax.annotation
包。@Resource
既可以注入 Bean,也可以注入 Java 原生资源(如文件、数据库连接等)。它的工作方式类似于 Spring 的@Autowired
注解,但有一些不同的特性和用途。
@Resource
-
按名称注入:
-
如果没有指定
name
属性,@Resource
会默认按照变量名去寻找匹配的 Bean。如果找到一个匹配的 Bean,就会进行注入。 -
如果指定了
name
属性,则按指定的名称查找 Bean 并注入。
@Resource(name = "myService") private MyService myService;
-
-
按类型注入:
-
如果没有指定
name
属性且找不到按名称匹配的 Bean,@Resource
会尝试按照类型进行注入。
@Resource private MyService myService;
-
与 @Autowired
的区别:
注入方式:
-
@Autowired
是 Spring 提供的注解,默认是按类型注入,也可以搭配@Qualifier
按名称注入。 -
@Resource
是 Java 标准注解,默认是按名称注入,如果没有指定名称则按类型注入。
依赖注入解析顺序:
-
@Resource
首先按名称查找 Bean,如果找不到再按类型查找。 -
@Autowired
直接按类型查找,除非使用@Qualifier
指定名称。
注解来源:
@Autowired
来自于 Spring 框架。
@Resource
来自于 Java EE(现在属于 Jakarta EE)。
@Inject
按照类型进行自动装配的
多个Bean对象进行依赖处理
1. @Qualifier
注解
@Qualifier
注解用于明确指定要注入的 Bean。当存在多个相同类型的 Bean 时,通过 @Qualifier
注解可以告诉 Spring 选择哪个具体的 Bean 进行注入。
使用方法
-
在构造方法中:
@Component public class MyService { private final MyRepository repository; @Autowired public MyService(@Qualifier("mySpecificRepository") MyRepository repository) { this.repository = repository; } // Other methods }
在这个例子中,
@Qualifier("mySpecificRepository")
指定了注入的 Bean 名称为mySpecificRepository
。 -
在 setter 方法中:
@Component public class MyService { private MyRepository repository; @Autowired public void setRepository(@Qualifier("mySpecificRepository") MyRepository repository) { this.repository = repository; } // Other methods }
同样,
@Qualifier("mySpecificRepository")
用于指定要注入的 Bean。 -
在字段中:
@Component public class MyService { @Autowired @Qualifier("mySpecificRepository") private MyRepository repository; // Other methods }
@Qualifier("mySpecificRepository")
直接用于字段注入,明确指定注入的 Bean。
2. @Primary
注解
@Primary
注解用于标记当存在多个相同类型的 Bean 时,Spring 默认注入哪个 Bean。如果没有使用 @Qualifier
注解进行显式指定,Spring 会优先注入被标记为 @Primary
的 Bean。
示例:
@Component
@Primary
public class MyPrimaryRepository implements MyRepository {
// Implementation details
}
@Component
public class MySecondaryRepository implements MyRepository {
// Implementation details
}
在这个例子中,MyPrimaryRepository
被标记为 @Primary
,因此如果在没有 @Qualifier
注解的情况下进行注入,Spring 会选择 MyPrimaryRepository
。
3. 自定义注解
在某些复杂的场景中,你可能需要自定义注解来标识不同的 Bean。例如,你可以创建自己的注解,并与 @Qualifier
注解结合使用。
自定义注解示例:
-
定义注解:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface MySpecialQualifier { }
-
使用注解:
@Component public class MyService { private final MyRepository repository; @Autowired public MyService(@MySpecialQualifier MyRepository repository) { this.repository = repository; } // Other methods }
在这个例子中,
@MySpecialQualifier
是一个自定义的注解,用于指定注入的 Bean。
4. 其他高级配置
在复杂应用中,你也可以使用 Java 配置类和 XML 配置文件来定义 Bean 的注入规则。例如,你可以在配置类中使用 @Bean
注解和方法参数来明确指定 Bean 的创建和依赖关系。
Java 配置类示例:
@Configuration
public class AppConfig {
@Bean
@Primary
public MyRepository myPrimaryRepository() {
return new MyPrimaryRepository();
}
@Bean
public MyRepository mySecondaryRepository() {
return new MySecondaryRepository();
}
}
在这个配置类中,通过 @Primary
注解和 @Bean
方法明确指定了默认的 Bean。
控制反转(IoC):
-
传统情况下,应用程序的各个组件通常会自己管理它们的依赖对象,称为"正向控制"。而在IoC中,这种控制被反转了。组件的依赖不再由它们自己创建或获取,而是由IoC容器负责注入,这样做可以解耦组件,使得代码更容易测试和维护。
依赖注入(DI,Dependency Injection):
-
IoC最常见的一种实现方式就是依赖注入。依赖注入是指在运行时,IoC容器将所需的依赖对象注入到组件中,而不是让组件自己去查找或创建这些对象。
-
DI可以通过构造器注入、Setter方法注入或接口注入等多种方式实现。
主要的实现步骤和原理
扫描和解析注解:
-
Spring 容器在启动时,会扫描指定的包路径下的类,查找带有
@Autowired
注解的字段、构造函数或方法。 -
Spring 使用反射技术来获取这些注解的元数据(如注解的类型、位置、修饰的元素等)。
依赖注入逻辑:
-
对于标记了
@Autowired
注解的字段、构造函数或方法,Spring 会尝试根据类型在容器中查找合适的 bean 实例。 -
如果找到唯一的匹配 bean,Spring 会将其注入到标记了
@Autowired
的位置。 -
如果有多个匹配的 bean,Spring 会尝试根据 bean 名称或其他限定符(如
@Qualifier
注解)来进一步筛选。如果仍然不能确定唯一的 bean,Spring 会抛出异常。
处理构造函数注入:
-
如果
@Autowired
应用于构造函数,并且类只有一个构造函数,则 Spring 会自动使用该构造函数进行注入,即使没有明确标注@Autowired
。 -
Spring 会自动解析构造函数的参数类型,并在容器中查找匹配的 bean 进行注入。
处理方法和字段注入:
-
对于方法,Spring 会调用该方法,并传入匹配的 bean 实例作为参数。
-
对于字段,Spring 会通过反射直接设置字段的值。
required 属性:
@Autowired
注解的required
属性默认为true
,这意味着如果没有找到匹配的 bean,Spring 会抛出NoSuchBeanDefinitionException
异常。如果
required
设置为false
,则在没有匹配的 bean 时,Spring 不会注入该字段或参数,保持其默认值(例如null
)。参考文章
-