什么是SpringIOC
IOC全拼是:inverion of Contro(控制反转),它是Spring框架的核心功能之一,是将对象的创建(new) ,初始化(initialization),对象生命周期的管理交给外部依赖完成,也就是IOC容器。
IOC解决的问题,也就是提出IOC的原因
最主要的是解决代码耦合性,如果不使用IOC,如果各个组件之间相互依赖有组件改变时,就要修改其他使用的地方,使用IOC让代码具有可重用性。
举例:
# 如果不使用IOC
private UserRepository userRepository = new UserRepository();
# 使用IOC
@Autowired 或者 @Resource
private UserRepository userRepository;
根据上面的例子发现,如果我们不实用IOC,就要一次一次的创建对象,使用了IOC只需要在IOC容器中去取我们已经创建并初始化好的对象即可,我们在IOC容器中取出对象一般使用的是@Autowired 或者 @Resource注解,其实这个过程就是依赖注入(Dependency Injection),这也是实现控制反转的一种方法,目录最后一个说的就是依赖注入的几种方式。
什么是IOC容器
IOC容器是管理对象(Bean)的一个东西,它负责了对象(Bean)的创建,初始化,配置并管理了对象的整个生命周期。
一般在我们的SpringBoot项目中,我们使用特定的注解,就会将对应的类对象创建好,并加载到IOC容器,比如常用的:@Component(标记在一些通用的组件上),@Service(标记在服务实现上),@Repository(标记在数据仓库类上),@RestController(标记在控制层)。
也可以通过配置类注解进行配置,例如:
@Configuration
public class AppConfig {
@Bean
public SomeService someService() {
return new SomeServiceImpl();
}
}
还有就是比较老的项目使用的Spring,通过XML的方式:
<beans>
<bean id="myService" class="com.example.MyService"/>
</beans>
上面就是我们代码中比较常见的例子,进行的对象的创建和配置,然后交给IOC容器管理。
实现IOC的两个接口:BeanFactory和ApplicationContext,它们俩都是IOC容器的实现,用于实例化,配置和管理Bean的生命周期。它俩之间有功能一样,但是ApplicationContext提供了更多的高级特性。
BeanFactory是Spring IOC容器最基本的容器,提供了依赖注入的功能,例如:延迟加载(可以通过注解:@Lazy 实现),最基本的依赖注入(构造器和属性依赖注入),Bean的生命周期管理,我们一般不单独使用BeanFactory,通常使用功能更高级的ApplicationContext。
ApplicationContext是BeanFactory的子接口,ApplicationContext继承了BeanFactory的所有特性,并增加了更多的企业特性,例如:国际化的支持,事件发布机制,AOP机制,声明式事务管理等等。
举例BeanFactory和ApplicationContext的基本使用:
# 通过BeanFactory在IOC容器中取对象
// 创建BeanFactory
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
// 从BeanFactory中取出Bean
MyService myService = (MyService) factory.getBean("myService");
// 使用Bean
myService.doSomething();
# 通过ApplicationContext在IOC容器中取对象
@Resource // 通过依赖注入的方式取这个ApplicationContext
ApplicationContext context;
public void test(String[] args) {
// 使用ApplicationContext
context.getBean("bean名字");
}
Bean(对象)的生命周期
Bean的生命周期指的就是Bean从创建到销毁的整个过程:
1. 实例化
我们上面举例的注解,@Component(标记在一些通用的组件上),@Service(标记在服务实现上),@Repository(标记在数据仓库类上),@RestController(标记在控制层)都会对类进行实例化,包括使用配置的方式。
@Configuration
public class AppConfig {
@Bean
public SomeService someService() {
return new SomeServiceImpl();
}
}
2.属性注入
属性注入就是给字段设置值,例如:
@Autowired
private AnotherBean beanOne;
下面讲到的依赖注入的几种方式都是属性注入。
3. 初始化
初始化中可以执行各种通知,前置方法,初始化方法,后置方法。
可以实现 InitializingBean
接口,进行自定义初始化,例如:
@Component
public class MyBean implements InitializingBean {
// 类的属性和方法...
@Override
public void afterPropertiesSet() throws Exception {
// 自定义的初始化方法
System.out.println("初始化操作...");
}
}
也可以使用@PostConstruct注解进行初始化,@PostConstruct注解的方法会在Bean属性被设置后调用,推荐使用。例子:
public class MyBean {
// 类的属性和方法...
@PostConstruct
public void init() {
// 自定义的初始化方法
System.out.println("初始化操作...");
}
}
还有很多初始化,不一一举例。
4. 使用Bean
通过ApplicationContext的方法取出对应的对象即可使用,或者使用属性注入,注入后的对象也可立马使用。例子:
@Resource // 通过依赖注入的方式取这个ApplicationContext
ApplicationContext context;
public void test(String[] args) {
// 使用ApplicationContext
context.getBean("bean名字");
}
@Resource
private UserRepository userRepository;
5. 销毁Bean
可以实现DisposableBean接口,自定义销毁逻辑
@Component
public class MyBean implements DisposableBean {
// 类的属性和方法...
@Override
public void destroy() throws Exception {
// 自定义的销毁方法
System.out.println("执行销毁逻辑...");
}
}
也可以使用@PreDestroy注解
@Component
public class MyBean {
// 类的属性和方法...
@PreDestroy
public void cleanup() {
// 自定义的销毁方法
System.out.println("执行销毁逻辑...");
}
}
依赖注入的几种方式
1. 我们上面提到的属性字段依赖注入
public class Car {
@Resource // 使用字段注入
private Engine engine;
// Car类的其他方法...
}
2. 构造器注入
在类的构造器标记依赖注入注解
private Engine engine;
@Autowired // 使用构造器注入
public Car(Engine engine) {
this.engine = engine;
}
3. setter注入
public class MyComponent {
private Dependency dependency;
@Autowired
public void setDependency(Dependency dependency) {
this.dependency = dependency;
}
// MyComponent的其他方法...
}