Spring IoC 依赖查找
方式
主要有以下几种方式:
- 根据 Bean 名称
- 实时查找
- 延迟查找(
ObjectFactory
以及ObjectProvider
提供,对生命周期有好处``
- 根据 Bean 类型
- 单个 Bean 对象
- 集合 Bean 对象
- 根据 Bean 名称 + 类型
根据 Java 注解查找
- 单个 Bean 对象
-
代码
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<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 id="user" class="com.mindartisan.spring.geek.ioc.overview.dependency.domain.User">
<property name="id" value="1"/>
<property name="name" value="Steve"/>
</bean>
<bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.dependency.domain.SuperUser" parent="user"
primary="true">
<property name="address" value="北京"/>
</bean>
<!-- 延迟查找使用 -->
<bean id="objectFactoryCreatingFactoryBean"
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
</beans>
User: ```java /**
- 用户 *
- @author mindartisan.blog.csdn.net
@date */ public class User {
private Long id;
private String name;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
@Override public String toString() { return “User{“ +
"id=" + id +
", name='" + name + '\'' +
'}';
} }
Super 注解:
java /**- super 注解 *
- @author mindartisan.blog.csdn.net
- @date
/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Super {
}
SuperUser:
java /* - 超级用户 *
- @author mindartisan.blog.csdn.net
@date */ @Super public class SuperUser extends User {
private String address;
public String getAddress() { return address; }
public void setAddress(String address) { this.address = address; }
@Override public String toString() { return “SuperUser{“ +
"address='" + address + '\'' +
"} " + super.toString();
} }
Main 方法:
java /**- 依赖查找演示 *
- @author mindartisan.blog.csdn.net
- @date */ public class DependencyLookUpDemo { public static void main(String[] args) { // 配置 XML 配置文件,两个方式均可 // 启动 Spring 应用上下文 BeanFactory beanFactory = new ClassPathXmlApplicationContext(“META-INF/dependency-lookup-context.xml”); // BeanFactory beanFactory = new ClassPathXmlApplicationContext(“classpath:/META-INF/dependency-lookup-context.xml”); lookupInRealTime(beanFactory); lookupInLazy(beanFactory); lookupSingleByType(beanFactory); lookupCollectionByType(beanFactory); lookupByAnnotationType(beanFactory); }
/**
* 通过名称:实时查找
*
* @param beanFactory bean工厂
*/
private static void lookupInRealTime(BeanFactory beanFactory) {
User user = (User) beanFactory.getBean("user");
System.out.println("通过名称,实时查找:" + user);
}
/**
* 通过名称:延迟查找
*
* @param beanFactory bean工厂
*/
private static void lookupInLazy(BeanFactory beanFactory) {
ObjectFactory<User> objectFactoryCreatingFactoryBean = (ObjectFactory<User>) beanFactory.getBean("objectFactoryCreatingFactoryBean");
User user = objectFactoryCreatingFactoryBean.getObject();
System.out.println("通过名称,延迟查找:" + user);
}
/**
* 按类型查找:单个 bean
*
* @param beanFactory bean工厂
*/
private static void lookupSingleByType(BeanFactory beanFactory) {
User user = beanFactory.getBean(User.class);
System.out.println("按类型查找,单个 bean:" + user);
}
/**
* 按类型查找:多个 bean
*
* @param beanFactory bean工厂
*/
private static void lookupCollectionByType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
// key 为 bean 名称
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("按类型查找,多个 bean:" + users);
}
}
/**
* 按注解查找
*
* @param beanFactory bean工厂
*/
private static void lookupByAnnotationType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
// key 为 bean 名称
Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
System.out.println("按注解查找:" + users);
}
}
}
<a name="C32iI"></a>
# Spring IoC 依赖注入
<a name="an5X4"></a>
## 方式
主要有以下几种方式:
1. 根据 Bean 名称
1. 根据 Bean 类型
1. 单个 Bean 对象
1. 集合 Bean 对象
3. 注入容器内建 Bean 对象
3. 注入非 Bean 对象
3. 注入类型
1. 实时注入
1. 延迟注入
<a name="cpskU"></a>
## 代码
配置文件:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!-- 通过导入复用 dependency-lookup-context.xml -->
<import resource="dependency-lookup-context.xml"/>
<bean id="userRepository"
class="com.mindartisan.spring.geek.ioc.overview.dependency.repository.UserRepository"
autowire="byType"> <!-- 自动装配 -->
<!--<!– 手动配置 –>-->
<!--<property name="users">-->
<!-- <util:list>-->
<!-- <ref bean="superUser"/>-->
<!-- <ref bean="user"/>-->
<!-- </util:list>-->
<!--</property>-->
</bean>
</beans>
UserRepository:
/**
* 用户信息库
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class UserRepository {
/**
* 内建的非 Bean 对象
*/
private BeanFactory beanFactory;
/**
* 自定义的 Bean 对象
*/
private Collection<User> users;
private ObjectFactory<User> userObjectFactory;
private ObjectFactory<ApplicationContext> applicationContextObjectFactory;
public BeanFactory getBeanFactory() {
return beanFactory;
}
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public Collection<User> getUsers() {
return users;
}
public void setUsers(Collection<User> users) {
this.users = users;
}
public ObjectFactory<User> getUserObjectFactory() {
return userObjectFactory;
}
public void setUserObjectFactory(ObjectFactory<User> userObjectFactory) {
this.userObjectFactory = userObjectFactory;
}
public ObjectFactory<ApplicationContext> getApplicationContextObjectFactory() {
return applicationContextObjectFactory;
}
public void setApplicationContextObjectFactory(ObjectFactory<ApplicationContext> applicationContextObjectFactory) {
this.applicationContextObjectFactory = applicationContextObjectFactory;
}
}
Main 方法:
/**
* 依赖注入演示
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class DependencyInjectDemo {
public static void main(String[] args) {
// 配置 XML 配置文件,两个方式均可
// 启动 Spring 应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency" +
"-injection-context.xml");
// BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/dependency-injection-context.xml");
// 自定义 Bean
UserRepository userRepository = beanFactory.getBean("userRepository", UserRepository.class);
//「[User{id=1, name='Steve'}, SuperUser{address='北京'} User{id=1, name='Steve'}]」
System.out.println(userRepository.getUsers());
// 获取对象依赖注入,输出:「org.springframework.beans.factory.support.DefaultListableBeanFactory@57baeedf: defining beans
// [user,superUser,objectFactoryCreatingFactoryBean,userRepository]; root of factory hierarchy」
// 内建的依赖
System.out.println(userRepository.getBeanFactory());
// 对比以下代码:
// 1. BeanFactory beanFactory
// 2. ObjectFactory<User> userObjectFactory
// 3. ObjectFactory<ApplicationContext>applicationContextObjectFactory
// 输出:「false」
System.out.println((userRepository.getBeanFactory() == beanFactory));
// 依赖查找:报错「No qualifying bean of type 'org.springframework.beans.factory.BeanFactory' available」
// 说明:BeanFactory.class 是内建的非 Bean 对象,内建的依赖
// System.out.println(beanFactory.getBean(BeanFactory.class));
// ObjectFactory<User> userObjectFactory <--> ObjectFactory<ApplicationContext>applicationContextObjectFactory
ObjectFactory userObjectFactory = userRepository.getUserObjectFactory();
// 输出 :「SuperUser{address='北京'} User{id=1, name='Steve'}」
System.out.println(userObjectFactory.getObject());
// 输出:「false」
System.out.println(userObjectFactory.getObject() == beanFactory);
ObjectFactory applicationContextObjectFactory = userRepository.getApplicationContextObjectFactory();
// 输出:「org.springframework.context.support.ClassPathXmlApplicationContext@6f75e721, started on Thu Dec 23
// 00:55:34 CST 2021」
System.out.println(applicationContextObjectFactory.getObject());
// 输出:「true」
// 说明:ObjectFactory 自动注入的时候给我们注入了 ApplicationContext
System.out.println(applicationContextObjectFactory.getObject() == beanFactory);
// 对比结束
// 容器内建 Bean,输出:「获取 Environment 类型的 Bean:StandardEnvironment {activeProfiles=[],……」
Environment environment = beanFactory.getBean(Environment.class);
System.out.println("获取 Environment 类型的 Bean:" + environment);
}
}
Spring IoC 依赖来源
来源
主要有以下:
- 自定义 Bean -> 比如:业务上的 Bean 对象
- 容器内建 Bean 对象 -> 比如:Environment.class
容器内建依赖 -> 比如:BeanFactory.class
代码
Spring IoC 配置元信息
Bean 定义配置
- 基于 XML 文件
- 基于 Properties 文件
- 基于 Java 注解
- 基于 Java API
- IoC 容器配置
- 基于 XML 文件
- 基于 Java 注解
- 基于 Java API
- 外部化属性配置
- 基于 Java 注解
Spring IoC 容器
来看下 Spring 文档:The
org.springframework.beans
andorg.springframework.context
packages are the basis for Spring Framework’s IoC container. The[BeanFactory](https://docs.spring.io/spring-framework/docs/5.2.12.RELEASE/javadoc-api/org/springframework/beans/factory/BeanFactory.html)
interface provides an advanced configuration mechanism capable of managing any type of object.[ApplicationContext](https://docs.spring.io/spring-framework/docs/5.2.12.RELEASE/javadoc-api/org/springframework/context/ApplicationContext.html)
is a sub-interface ofBeanFactory
. 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 theApplicationContext
adds more enterprise-specific functionality. TheApplicationContext
is a complete superset of theBeanFactory
and is used exclusively in this chapter in descriptions of Spring’s IoC container. For more information on using theBeanFactory
instead of theApplicationContext
, see[BeanFactory](https://docs.spring.io/spring-framework/docs/5.2.12.RELEASE/spring-framework-reference/core.html#beans-beanfactory)
.
- 基于 Java 注解
大概意思就是说 BeanFactory 是 ApplicationContext 的父接口,提供了基本功能,而后者添加了更多的企业性的特性:
- 更方便基础 Spring AOP 特性
- 国际化处理
- 事件发布
- 提供了特定的上下文
可以看下 UML 图验证:
简单来个结论:
- BeanFactory 是 Spring 底层的 IoC 容器
- 从功能上来说,ApplicationContext 是 BeanFactory 的超集
-
Spring 应用上下文
ApplicationContext 接口除了上述的「容器」的功能,还有以下功能:
面向切面(AOP)
- 配置元信息(Configuration Metadata)
- 资源管理(Resources)
- 事件(Events)
- 国际化(il8n)
- 注解(Annotations)
Environment 抽象(Environment Abstraction)
使用 Spring IoC 容器
使用 BeanFactory
此处的
DefaultListableBeanFactory
为BeanFactory
的实现:**
* BeanFactory 作为 IoC 容器示例
*
* @author mindartisan.blog.csdn.net
* @date
*/
public class BeanFactoryAsIoCContainerDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
String location = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载配置
int beanDefinitionsCount = reader.loadBeanDefinitions(location);
System.out.println("Bean 定义加载的数量:"+beanDefinitionsCount);
// 依赖查找集合对象
// 简单说明不用 ApplicationContext 的时候也能加载 Bean
lookupCollectionByType(defaultListableBeanFactory);
}
/**
* 按类型查找:多个 bean
*
* @param beanFactory bean工厂
*/
private static void lookupCollectionByType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
// key 为 bean 名称
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("按类型查找,多个 bean:" + users);
}
}
}
使用 ApplicationContext
此处的
AnnotationConfigApplicationContext
为ApplicationContext
的实现:```java /**
- 注解能力的 ApplicationContext 作为 IoC 容器示例 *
- @author mindartisan.blog.csdn.net
@date */ @Configuration public class AnnotationApplicationContextAsIoCContainerDemo { public static void main(String[] args) { // 创建 BeanFactory 容器 AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(); // 将当前类作为配置类 annotationConfigApplicationContext.register(AnnotationApplicationContextAsIoCContainerDemo.class); annotationConfigApplicationContext.refresh(); // 依赖查找集合对象 // 使用 AnnotationConfigApplicationContext 当做 IoC 容器 lookupCollectionByType(annotationConfigApplicationContext); }
@Bean public User user() { User user = new User(); user.setId(1L); user.setName(“Steve”); return user; }
/**
- 按类型查找:多个 bean *
- @param beanFactory bean工厂
*/
private static void lookupCollectionByType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
} } }ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
// key 为 bean 名称
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("按类型查找,多个 bean:" + users);
<a name="NffWX"></a>
# Spring IoC 容器生命周期
<a name="cMnCL"></a>
## 启动
<a name="G7Ilw"></a>
### AbstractApplicationContext#refresh()
```java
public void refresh() throws BeansException, IllegalStateException {
// 不知道当前用户的线程安全不安全
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 准备阶段
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 让子类去刷新内置的 BeanFactory,
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 加载 bean,但不实例化 bean:
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 调用在上下文中注册为 bean的 factory processor,BeanFactory 扩展点
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 实例化并注册所有 BeanPostProcessor bean,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.
// 初始化特定上下文的其他特殊 bean
onRefresh();
// Check for listener beans and register them.
// 注册监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所有的单例 bean
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.
// 有异常了销毁 bean
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();
}
}
}
AbstractApplicationContext#prepareRefresh()
protected void prepareRefresh() {
// Switch to active.
// 记录启动时间,算运行时间
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// 初始化 PropertySources
// Initialize any placeholder property sources in the context environment.
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
// 校验需要的 Properties
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
停止
AbstractApplicationContext#close()
public void close() {
synchronized (this.startupShutdownMonitor) {
// 关闭
doClose();
// If we registered a JVM shutdown hook, we don't need it anymore now:
// We've already explicitly closed the context.
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}
catch (IllegalStateException ex) {
// ignore - VM is already shutting down
}
}
}
}
AbstractApplicationContext#doClose()
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.
// 销毁 bean
destroyBeans();
// Close the state of this context itself.
// 关闭 BeanFactory
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);
}
}