IoC(Inversion of Control,控制反转)是Spring框架的核心部分,是一种设计思想,而不是一个具体的技术实现。它通过将对象创建和管理的控制权从应用代码转移到Spring容器中,实现了松耦合设计。以下是对Spring IoC的详细解释:
IoC容器(Inversion of Control Container)是一种用于实现IoC(控制反转)设计模式的工具。它负责创建、配置和管理对象及其依赖关系,自动完成对象的创建、初始化、注入等操作,从而简化开发流程,提高开发效率。
IoC容器的主要职责包括:
IoC容器的工作流程主要包括配置、容器初始化、依赖注入和对象使用四个阶段:
在Spring框架中,IoC容器可以通过XML配置文件、注解或Java配置类来创建对象。下面分别介绍下这三种方式的实现样例。
(1)XML配置
<!-- 引入Spring的命名空间,定义Bean及其依赖关系 -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 定义一个Bean -->
<bean id="userService" class="com.example.service.UserServiceImpl">
<!-- 配置依赖 -->
<property name="userDao" ref="userDao"/>
</bean>
<!-- 定义另一个Bean -->
<bean id="userDao" class="com.example.dao.UserDaoImpl"/>
</beans>
在这个例子中,我们定义了两个Bean:userService和userDao。
userService依赖于userDao,我们通过<property>元素将userDao的实例注入到userService中。
ref属性用于引用另一个Bean的ID。
(2)注解配置
1. 首先,确保你已经在Spring配置文件中开启了注解扫描:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.example"/>
</beans>
2. 然后,在你的类上使用@Component、@Service、@Repository或@Controller等注解来标记它们为Spring管理的Bean:
@Service
public class UserServiceImpl implements UserService {
private final UserDao userDao;
@Autowired // 自动装配依赖
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
// ...
}
在上面的代码中,@Service注解表明UserServiceImpl是一个服务层的Bean,
而@Autowired注解则用于自动装配UserDao依赖。Spring容器在启动时会扫描指定的包路径,
查找带有上述注解的类,并将它们注册为Bean。
(3)Java配置类
Spring容器在启动时会扫描带有@Configuration注解的类,并执行所有标记有@Bean注解的方法,创建相应的Bean,并管理它们的生命周期。
// 标记为@Configuration的类告诉Spring这是一个配置类
@Configuration
public class AppConfig {
// 使用@Bean注解创建并返回一个对象,这个对象将作为Spring容器中的Bean
@Bean
public AnotherDependency anotherDependency() {
return new AnotherDependency();
}
@Bean
public ExampleService exampleService(AnotherDependency anotherDependency) {
ExampleService exampleService = new ExampleService();
exampleService.setAnotherDependency(anotherDependency);
return exampleService;
}
}
在这个例子中,anotherDependency方法创建了AnotherDependency的一个实例。
然后在exampleService方法中,AnotherDependency实例被作为参数传入,并设置给ExampleService实例。
这样,Spring容器就会处理ExampleService的依赖注入。
Spring IoC容器的源码解析可以从以下几个核心组件入手:
(1)BeanDefinition
BeanDefinition是描述Bean的元数据,包括Bean的类型、作用域、构造函数参数、依赖关系等。它是一个接口,具体实现类如RootBeanDefinition和ChildBeanDefinition等。
Spring IOC容器从各种源加载BeanDefinition,主要包括XML文件、注解和Java配置。
(2)BeanFactory和ApplicationContext
BeanFactory是IOC容器的核心接口,负责Bean的实例化、配置和组装。ApplicationContext是BeanFactory的子接口,提供了更多的企业级功能,如事件传播、资源加载等。
创建的BeanDefinition需要注册到容器内部,以便后续能够创建对应的Bean实例。这步便是由BeanFactory来实现的,所有的BeanDefinition都存储在其内部的Map中,键为Bean的名字,值为BeanDefinition对象。
(3)容器的启动
容器启动的入口通常是通过ClassPathXmlApplicationContext或AnnotationConfigApplicationContext等实现类的构造函数开始的,它们会初始化BeanFactory,加载BeanDefinition,并注册Bean。
(4)BeanDefinitionRegistryPostProcessor
这个接口允许在注册BeanDefinition之后、实例化Bean之前进行自定义的处理,如动态添加BeanDefinition或修改已有的BeanDefinition。
(5)实例化Bean
AbstractBeanFactory类是BeanFactory的一个抽象实现类,它提供了创建Bean的基本方法。其中doGetBean方法是创建Bean的核心,它会根据Bean的名字和类型从内部的Map中获取BeanDefinition,然后通过createBean方法实例化Bean。
(6)依赖注入
依赖注入是通过InstantiationStrategy接口实现的。对于简单的Bean,通常使用默认的SimpleInstantiationStrategy;对于需要代理的Bean,则会使用CglibSubclassingInstantiationStrategy。
(7)Bean的生命周期
在Bean实例化和依赖注入之后,Spring会调用initMethodName指定的初始化方法(如afterPropertiesSet)。在Bean被销毁之前,会调用destroyMethodName指定的销毁方法(如destroy)。
(8)AOP代理
Spring支持面向切面编程(AOP),通过ProxyFactory和AopProxy接口创建代理,将横切关注点应用到目标Bean上。
DI(Dependency Injection,依赖注入)是实现IoC(Inversion of Control,控制反转)的一种方式或手段。其核心理念在于,组件之间的依赖关系不是由组件本身在编译时静态决定的,而是由IoC容器在运行期动态地将依赖关系注入到组件之中。通过依赖注入,组件类不再直接依赖于其依赖对象的具体实现,而是依赖于抽象(如接口),从而实现了组件类和其依赖对象的解耦。这种解耦使得组件类的代码更加整洁,也更易于测试和维护。
Spring支持三种主要的依赖注入方式:构造器注入、Setter注入和字段注入。
@Component
public class ExampleService {
private final AnotherDependency anotherDependency;
@Autowired
public ExampleService(AnotherDependency anotherDependency) {
this.anotherDependency = anotherDependency;
}
}
@Component
public class ExampleService {
private AnotherDependency anotherDependency;
@Autowired
public void setAnotherDependency(AnotherDependency anotherDependency) {
this.anotherDependency = anotherDependency;
}
}
@Component
public class ExampleService {
@Autowired
private AnotherDependency anotherDependency;
}