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");// 自定义 BeanUserRepository 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>applicationContextObjectFactoryObjectFactory 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 自动注入的时候给我们注入了 ApplicationContextSystem.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.beansandorg.springframework.contextpackages 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
WebApplicationContextfor use in web applications.
In short, the
BeanFactoryprovides the configuration framework and basic functionality, and theApplicationContextadds more enterprise-specific functionality. TheApplicationContextis a complete superset of theBeanFactoryand is used exclusively in this chapter in descriptions of Spring’s IoC container. For more information on using theBeanFactoryinstead 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 的时候也能加载 BeanlookupCollectionByType(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()```javapublic 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.// 初始化特定上下文的其他特殊 beanonRefresh();// Check for listener beans and register them.// 注册监听器registerListeners();// Instantiate all remaining (non-lazy-init) singletons.// 实例化所有的单例 beanfinishBeanFactoryInitialization(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.// 有异常了销毁 beandestroyBeans();// 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// 校验需要的 PropertiesgetEnvironment().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.// 销毁 beandestroyBeans();// Close the state of this context itself.// 关闭 BeanFactorycloseBeanFactory();// 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);}}
