参考: https://blog.csdn.net/ivan820819/article/details/79744797
IOC概念
- IOC(Inversion of Control), 控制反转, 指获得依赖对象的过程被反转了, 由原来的自身管理(主动)变为由IOC容器注入(被动)
- DI(Dependency Injection), 依赖注入, 由IOC容器在运行期间, 动态的将依赖关系注入到对象中
- 依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。
核心: 借助于”第三方”实现具有依赖关系的对象之间的解耦.
补充:
- IOC的实现策略有依赖查找和依赖注入
IOC职责
依赖处理
依赖查找
依赖注入
生命周期管理
容器
托管的资源(Java Beans或其他资源)
配置
容器
外部化配置
托管的资源(Java Beans或其他资源)
依赖查找与依赖注入的对比
- 构造器注入与setter注入对比
构造器注入能够在构造期创建一个完整合法的对象, 更符合对象创建即不变的设计理念, 增强系统的稳定以及便利性.
Spring IOC 依赖查找
- 根据Bean名称查找
- 实时查找
- 延迟查找
- 根据Bean类型查找
- 单个Bean对象
- 集合Bean对象
- 根据Bean名称+类型查找
- 根据Java注解查找
- 单个Bean对象
- 集合Bean对象
public static void main(String[] args) {
// 配置XML配置文件, 启动Spring应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext(
"classpath:META-INF/dependency-lookup-context.xml");
// 通过名称查找
// lookUpInRealTime(beanFactory);
// lookUpInLazy(beanFactory);
// 通过类型查找
lookUpByType(beanFactory);
lookUpByCollectionType(beanFactory);
// 通过注解查找
lookUpByAnnotation(beanFactory);
}
private static void lookUpInRealTime(BeanFactory beanFactory) {
User user = (User) beanFactory.getBean("user");
System.out.println("根据名称实时查找: " + user);
}
private static void lookUpInLazy(BeanFactory beanFactory) {
ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
User user = objectFactory.getObject();
System.out.println("根据名称延迟查找: " + user);
}
private static void lookUpByType(BeanFactory beanFactory) {
User user = beanFactory.getBean(User.class);
System.out.println("根据类型实时查找: " + user);
}
private static void lookUpByCollectionType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("根据类型查找集合对象: " + users);
}
}
private static void lookUpByAnnotation(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
System.out.println("根据类型查找集合对象: " + users);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="user" class="top.xinzhang0618.ioc.overview.domain.User" primary="true">
<property name="id" value="1"/>
<property name="name" value="xinzhang"/>
</bean>
<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
<bean id="superUser" class="top.xinzhang0618.ioc.overview.domain.SuperUser" parent="user">
<property name="address" value="shenzhen"/>
</bean>
</beans>
实体如下
public class User {
private Long id;
private String name;
...
}
@Super
public class SuperUser extends User {
private String address;
...
}
/**
* 标记超级
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Super {
}
ObjectFactoryBean, FactoryBean, BeanFactory三者有什么区别?
ObjectFactory 通常是针对单类 Bean 做延迟获取的,BeanFactory 则是全局 Bean 管理的容器。
Spring IOC依赖注入
- 根据Bean名称注入
- 根据Bean类型注入
- 单个Bean对象
- 集合Bean对象
- 注入容器内建Bean对象
- 注入非Bean对象
- 注入类型
- 实时注入
- 延迟注入
如下示例, 可以手动配置, 也可以通过Autowire进行注入
<bean id="userRepository" class="org.geekbang.thinking.in.spring.ioc.overview.repository.UserRepository"
autowire="byType"> <!-- Auto-Wiring -->
<!-- 手动配置 -->
<!-- <property name="users">-->
<!-- <util:list>-->
<!-- <ref bean="superUser" />-->
<!-- <ref bean="user" />-->
<!-- </util:list>-->
<!-- </property>-->
</bean>
Spring IOC依赖来源
- 自定义Bean(自己用xml配置或注解配置的bean)
- 内部容器依赖的Bean(非自己定义的Bean,spring容器初始化的Bean), 如Environment对象
内部容器所构建的依赖(非Bean,不可通过获取依赖查找Bean的方法来获取(getBean(XXX)))
public class UserRepository {
private Collection<User> users; // 自定义 Bean
private BeanFactory beanFactory; // 內建非 Bean 对象(依赖)
...
}
内建Bean和内建依赖如何区别?
实际上,内建的 Bean 是普通的 Spring Bean,包括 BeanDefinitions 和 Singleton Objects,而内建依赖则是通过 AutowireCapableBeanFactory 中的 resolveDependency 方法来注册,这并非是一个 Spring Bean,无法通过依赖查找获取~
内部容器构建的依赖指的是什么?
Spring IoC 底层容器就是指的 BeanFactory 的实现类,大多数情况是 DefaultListableBeanFactory 这个类,它来管理 Spring Beans,而 ApplicationContext 通常为开发人员接触到的 IoC 容器,它是一个 Facade,Wrap 了 BeanFactory 的实现。
Java Bean 是一种功能组件,它是 Java对象的方式封装, 所谓依赖就是被组合的对象。
Spring IOC配置元信息
- Bean定义配置
- 基于XML文件
- 基于Properties文件
- 基于JAVA注解
- 基于JAVA API
- IOC容器配置
- 基于XML文件
- 基于JAVA注解
- 基于JAVA API
- 外部化属性配置
- 基于JAVA注解, 比如@Value
Spring IOC容器
BeanFacrtory和ApplicationContext谁才是IOC容器?
官方文档如下图
简要翻译: BeanFactory提供了管理对象的一些高级配置特性, ApplicationContext是BeanFactory的子接口, 它添加了:
- 更容易与Spring AOP的整合
- 消息资源的处理(用于国际化)
- 事件发布
- 应用级别的上下文, 比如应用在WEB应用的WebApplicationContext
总结: BeanFactory是个基本的IOC容器, ApplicationContext是在其基础上提供了更多企业级特性的超集.
分析下实现:
- ApplicationContext继承了BeanFactory
- ConfigurableApplicationContext中, 有个getBeanFactory()方法, 在AbstractRefreshableApplicationContext中有实现, 返回的是AbstractRefreshableApplicationContext持有的DefaultListableBeanFactory
- 即ApplicationContext是委托DefaultListableBeanFactory来操作getBean等方法的
BeanFactory和ApplicationContext的关系,从设计模式上讲, 使用了代理模式,也使用了面门模式。
Spring应用上下文
使用Spring IOC
- BeanFactory是Spring底层的IOC容器
- ApplicationContext是具备应用特性的BeanFactory超集
两者的使用场景区别, 简单来说就是如果只用xml进行Bean的简单配置, 用BeanFactory即可, 如果要用到一些高级特性比如注解方式的Bean配置, 那么需要用ApplicationContext, 注解方式配置的demo如下
public class AnnotationApplicationContextAsIocContainerDemo {
public static void main(String[] args) {
// 创建BeanFactory容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 将当前类作为配置类
context.register(AnnotationApplicationContextAsIocContainerDemo.class);
context.refresh();
// 依赖查找集合对象
lookUpByCollectionType(context);
}
@Bean
public User user() {
User user = new User();
user.setId(1L);
user.setName("hhh");
return user;
}
private static void lookUpByCollectionType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("根据类型查找集合对象: " + users);
}
}
}
Spring IOC容器的生命周期
一般分三阶段: 启动, 运行, 停止
启动看applicationContext.refresh()方法
以下为AbstractApplicationContext源码, 可以看到启动有几个操作:
- 初始化BeanFactory
- 触发BeanFactory的后续处理
- 注册Bean的后续处理器
- 初始化国际化相关
- 初始化事件广播
- 注册监听器
…
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 这里加入了Bean以及内建的非Bean对象(如BeanFactory)等依赖
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 这里可以自定义BeanFactory的拓展
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 这里可以自定义Bean的拓展
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
停止看applicationContext.close()方法
以下为AbstractApplicationContext源码, 可以看到停止主要有几个操作:
- 注销Bean
- 关闭BeanFactory
- 还有个onClose()空实现可以拓展
…
protected void doClose() {
// Check whether an actual close attempt is necessary...
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (logger.isDebugEnabled()) {
logger.debug("Closing " + this);
}
LiveBeansView.unregisterApplicationContext(this);
try {
// Publish shutdown event.
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
// Stop all Lifecycle beans, to avoid delays during individual destruction.
if (this.lifecycleProcessor != null) {
try {
this.lifecycleProcessor.onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
}
// Destroy all cached singletons in the context's BeanFactory.
destroyBeans();
// Close the state of this context itself.
closeBeanFactory();
// Let subclasses do some final clean-up if they wish...
onClose();
// Reset local application listeners to pre-refresh state.
if (this.earlyApplicationListeners != null) {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Switch to inactive.
this.active.set(false);
}
}
面试题
什么是Spring IOC容器?
Spring IOC容器是Spring使用依赖注入和依赖查找对IOC原则的一种实现, 同时Spring IOC还提供了一些其他的特性, 比如容器生命周期的管理, 容器的配置, 外部化配置等等.
BeanFactory与FactoryBean的区别?
BeanFactory是IOC底层容器, FactoryBean是创建Bean的一种方式, 帮助实现复杂的初始化逻辑
Spring Bean有两种实现,普通Bean,和工厂Bean(FactoryBean) 实现工厂Bean的方法就是pojo继承FactoryBean,并实现他的方法,当容器通过getBean()获取bean时,返回的是实现的getObject()方法所返回的对象