第三章 Spring IoC 容器概述
依赖查找
- 单一类型 实时查找
<bean id="user" class="org.xxx.domain.User">
<property name="id" value="1"/>
<property name="name" value="法外狂徒张三"/>
</bean>
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup-context.xml");
User user = (User) beanFactory.getBean("user");
User user = beanFactory.getBean(User.class);
- 单一类型 延迟查找
<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
User user = objectFactory.getObject();
- 集合类型 实时查找
<bean id="superUser" class="org.xxx.domain.SuperUser" parent="user"
primary="true">
<property name="address" value="杭州"/>
</bean>
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
}
依赖注入
- xml 手动注入
<bean id="userRepository" class="com.xxx.repository.UserRepository">
<!-- 手动配置 -->
<property name="users">
<util:list>
<ref bean="superUser"/>
<ref bean="user"/>
</util:list>
</property>
</bean>
public class UserRepository {
private Collection<User> users; // 自定义 Bean
public Collection<User> getUsers() {
return users;
}
public void setUsers(Collection<User> users) {
this.users = users;
}
}
- xml 自动注入
<bean id="userRepository" class="com.xxx.repository.UserRepository"
autowire="byType"> <!-- Auto-Wiring -->
</bean>
public class UserRepository {
private Collection<User> users; // 自定义 Bean
public Collection<User> getUsers() {
return users;
}
public void setUsers(Collection<User> users) {
this.users = users;
}
}
// Test Class
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");
// 依赖来源一:自定义 Bean
UserRepository userRepository = applicationContext.getBean("userRepository", UserRepository.class);
System.out.println(userRepository.getUsers());
}
- 容器内建 bean 对象
public class UserRepository {
private BeanFactory beanFactory; // 內建非 Bean 对象(依赖)
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
}
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");
UserRepository userRepository = applicationContext.getBean("userRepository", UserRepository.class);
// 依赖来源二:依赖注入(內建依赖)
System.out.println(userRepository.getBeanFactory()); // org.springframework.beans.factory.support.DefaultListableBeanFactory@6b143ee9
System.out.println(userRepository.getBeanFactory() == applicationContext.getBeanFactory()); // true
// 依赖查找
System.out.println(applicationContext.getBean(BeanFactory.class)); // No qualifying bean of type 'org.springframework.beans.factory.BeanFactory' available
// 依赖来源是否一致?
// 为何依赖注入可以得到,而依赖查找得不到 beanFactory 对象?
}
非实时注入
public class UserRepository {
private ObjectFactory<ApplicationContext> objectFactory;
public ObjectFactory<ApplicationContext> getObjectFactory() {
return objectFactory;
}
public void setObjectFactory(ObjectFactory<ApplicationContext> objectFactory) {
this.objectFactory = objectFactory;
}
}
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");
UserRepository userRepository = applicationContext.getBean("userRepository", UserRepository.class);
ObjectFactory userFactory = userRepository.getObjectFactory();
System.out.println(userFactory.getObject() == applicationContext); // true
}
- 依赖来源
- 自定义 Bean 对象
- UserRepository
- 容器内建 Bean 对象
- Environment
- 支持依赖查找
- 容器内建依赖(非 Bean 对象)
- BeanFactory
- 可以依赖注入得到,但依赖查找不到
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");
// 依赖来源三:容器內建 Bean
Environment environment = applicationContext.getBean(Environment.class);
System.out.println("获取 Environment 类型的 Bean:" + environment); // StandardEnvironment
}
配置元信息
Bean 定义
配置- 基于 XML 文件
- 基于 Java 注解
- 基于 Properties 文件
- 基于 Java API
Ioc 容器
配置- 基于 XML 文件
- 基于 Java 注解
- 基于 Java API
- 外部化属性配置
- 基于 Java 注解
Bean 定义 – 基于 XML 文件
Bean 定义 – 基于 Java 注解
Bean 定义 – 基于 Properties 文件
BeanFactory 和 ApplicationContext 谁才是 Spring ioc 容器 ?
The BeanFactory
interface provides an advanced configuration mechanism capable of managing any type of object. ApplicationContext
is a sub-interface
of BeanFactory. It adds:
- Easier integration with Spring’s AOP features
- Message resource handling (for use in internationalization)
- Event publication
- Application-layer specific contexts such as the WebApplicationContext for use in web applications.
In short, the BeanFactory provides the configuration framework and basic functionality, and the ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of Spring’s IoC container.
https://docs.spring.io/spring/docs/5.3.0-SNAPSHOT/spring-framework-reference/core.html#beans-introduction
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
@Nullable
String getId();
String getApplicationName();
String getDisplayName();
long getStartupDate();
@Nullable
ApplicationContext getParent();
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
@Nullable
private Boolean allowBeanDefinitionOverriding;
@Nullable
private Boolean allowCircularReferences;
@Nullable
private DefaultListableBeanFactory beanFactory;
private final Object beanFactoryMonitor = new Object();
public AbstractRefreshableApplicationContext() {
}
// ...
}
看似继承,实际上是组合
!!!类似于代理
ApplicationContext
BeanFactory 和 ApplicationContext 的应用
public class BeanFactoryAsIoCContainerDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// XML 配置文件 ClassPath 路径
String location = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载配置
int beanDefinitionsCount = reader.loadBeanDefinitions(location);
System.out.println("Bean 定义加载的数量:" + beanDefinitionsCount);
// 依赖查找集合对象
lookupCollectionByType(beanFactory);
}
private static void lookupCollectionByType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("查找到的所有的 User 集合对象:" + users);
}
}
}
@Configuration
public class AnnotationApplicationContextAsIoCContainerDemo {
/**
* 通过 Java 注解的方式,定义了一个 Bean
*/
@Bean
public User user() {
User user = new User();
user.setId(1L);
user.setName("张三");
return user;
}
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 将当前类 AnnotationApplicationContextAsIoCContainerDemo 作为配置类(Configuration Class)
applicationContext.register(AnnotationApplicationContextAsIoCContainerDemo.class);
// 启动应用上下文
applicationContext.refresh();
// 依赖查找集合对象
lookupCollectionByType(applicationContext);
// 关闭应用上下文
applicationContext.close();
}
private static void lookupCollectionByType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("查找到的所有的 User 集合对象:" + users);
}
}
}
Ioc 容器的启动、运行和停止
启动
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
// ...
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
// ...
}
总结
什么是 Spring Ioc 容器?
BeanFactory 与 FactoryBean?
BeanFactory 是 IoC 底层容器;
FactoryBean 是创建 Bean 的一种方式,帮助实现复杂的初始化逻辑;
Spring IoC 容器启动时做了哪些准备?
- IoC 配置元信息读取与解析
- IoC 容器生命周期
- Spring 事件发布
- 国际化
- 等等