Spring IoC 依赖查找

方式

主要有以下几种方式:

  1. 根据 Bean 名称
    1. 实时查找
    2. 延迟查找(ObjectFactory以及 ObjectProvider 提供,对生命周期有好处``
  2. 根据 Bean 类型
    1. 单个 Bean 对象
    2. 集合 Bean 对象
  3. 根据 Bean 名称 + 类型
  4. 根据 Java 注解查找

    1. 单个 Bean 对象
    2. 集合 Bean 对象

      代码

      配置文件:

      1. <?xml version="1.0" encoding="UTF-8"?>
      2. <beans xmlns="http://www.springframework.org/schema/beans"
      3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      5. <bean id="user" class="com.mindartisan.spring.geek.ioc.overview.dependency.domain.User">
      6. <property name="id" value="1"/>
      7. <property name="name" value="Steve"/>
      8. </bean>
      9. <bean id="superUser" class="com.mindartisan.spring.geek.ioc.overview.dependency.domain.SuperUser" parent="user"
      10. primary="true">
      11. <property name="address" value="北京"/>
      12. </bean>
      13. <!-- 延迟查找使用 -->
      14. <bean id="objectFactoryCreatingFactoryBean"
      15. class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
      16. <property name="targetBeanName" value="user"/>
      17. </bean>
      18. </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{“ +

      1. "id=" + id +
      2. ", name='" + name + '\'' +
      3. '}';

      } } 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{“ +

      1. "address='" + address + '\'' +
      2. "} " + 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); }
  1. /**
  2. * 通过名称:实时查找
  3. *
  4. * @param beanFactory bean工厂
  5. */
  6. private static void lookupInRealTime(BeanFactory beanFactory) {
  7. User user = (User) beanFactory.getBean("user");
  8. System.out.println("通过名称,实时查找:" + user);
  9. }
  10. /**
  11. * 通过名称:延迟查找
  12. *
  13. * @param beanFactory bean工厂
  14. */
  15. private static void lookupInLazy(BeanFactory beanFactory) {
  16. ObjectFactory<User> objectFactoryCreatingFactoryBean = (ObjectFactory<User>) beanFactory.getBean("objectFactoryCreatingFactoryBean");
  17. User user = objectFactoryCreatingFactoryBean.getObject();
  18. System.out.println("通过名称,延迟查找:" + user);
  19. }
  20. /**
  21. * 按类型查找:单个 bean
  22. *
  23. * @param beanFactory bean工厂
  24. */
  25. private static void lookupSingleByType(BeanFactory beanFactory) {
  26. User user = beanFactory.getBean(User.class);
  27. System.out.println("按类型查找,单个 bean:" + user);
  28. }
  29. /**
  30. * 按类型查找:多个 bean
  31. *
  32. * @param beanFactory bean工厂
  33. */
  34. private static void lookupCollectionByType(BeanFactory beanFactory) {
  35. if (beanFactory instanceof ListableBeanFactory) {
  36. ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
  37. // key 为 bean 名称
  38. Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
  39. System.out.println("按类型查找,多个 bean:" + users);
  40. }
  41. }
  42. /**
  43. * 按注解查找
  44. *
  45. * @param beanFactory bean工厂
  46. */
  47. private static void lookupByAnnotationType(BeanFactory beanFactory) {
  48. if (beanFactory instanceof ListableBeanFactory) {
  49. ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
  50. // key 为 bean 名称
  51. Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
  52. System.out.println("按注解查找:" + users);
  53. }
  54. }

}

  1. <a name="C32iI"></a>
  2. # Spring IoC 依赖注入
  3. <a name="an5X4"></a>
  4. ## 方式
  5. 主要有以下几种方式:
  6. 1. 根据 Bean 名称
  7. 1. 根据 Bean 类型
  8. 1. 单个 Bean 对象
  9. 1. 集合 Bean 对象
  10. 3. 注入容器内建 Bean 对象
  11. 3. 注入非 Bean 对象
  12. 3. 注入类型
  13. 1. 实时注入
  14. 1. 延迟注入
  15. <a name="cpskU"></a>
  16. ## 代码
  17. 配置文件:
  18. ```xml
  19. <?xml version="1.0" encoding="UTF-8"?>
  20. <beans xmlns="http://www.springframework.org/schema/beans"
  21. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
  22. 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">
  23. <!-- 通过导入复用 dependency-lookup-context.xml -->
  24. <import resource="dependency-lookup-context.xml"/>
  25. <bean id="userRepository"
  26. class="com.mindartisan.spring.geek.ioc.overview.dependency.repository.UserRepository"
  27. autowire="byType"> <!-- 自动装配 -->
  28. <!--&lt;!&ndash; 手动配置 &ndash;&gt;-->
  29. <!--<property name="users">-->
  30. <!-- <util:list>-->
  31. <!-- <ref bean="superUser"/>-->
  32. <!-- <ref bean="user"/>-->
  33. <!-- </util:list>-->
  34. <!--</property>-->
  35. </bean>
  36. </beans>

UserRepository:

  1. /**
  2. * 用户信息库
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class UserRepository {
  8. /**
  9. * 内建的非 Bean 对象
  10. */
  11. private BeanFactory beanFactory;
  12. /**
  13. * 自定义的 Bean 对象
  14. */
  15. private Collection<User> users;
  16. private ObjectFactory<User> userObjectFactory;
  17. private ObjectFactory<ApplicationContext> applicationContextObjectFactory;
  18. public BeanFactory getBeanFactory() {
  19. return beanFactory;
  20. }
  21. public void setBeanFactory(BeanFactory beanFactory) {
  22. this.beanFactory = beanFactory;
  23. }
  24. public Collection<User> getUsers() {
  25. return users;
  26. }
  27. public void setUsers(Collection<User> users) {
  28. this.users = users;
  29. }
  30. public ObjectFactory<User> getUserObjectFactory() {
  31. return userObjectFactory;
  32. }
  33. public void setUserObjectFactory(ObjectFactory<User> userObjectFactory) {
  34. this.userObjectFactory = userObjectFactory;
  35. }
  36. public ObjectFactory<ApplicationContext> getApplicationContextObjectFactory() {
  37. return applicationContextObjectFactory;
  38. }
  39. public void setApplicationContextObjectFactory(ObjectFactory<ApplicationContext> applicationContextObjectFactory) {
  40. this.applicationContextObjectFactory = applicationContextObjectFactory;
  41. }
  42. }

Main 方法:

  1. /**
  2. * 依赖注入演示
  3. *
  4. * @author mindartisan.blog.csdn.net
  5. * @date
  6. */
  7. public class DependencyInjectDemo {
  8. public static void main(String[] args) {
  9. // 配置 XML 配置文件,两个方式均可
  10. // 启动 Spring 应用上下文
  11. BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency" +
  12. "-injection-context.xml");
  13. // BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/dependency-injection-context.xml");
  14. // 自定义 Bean
  15. UserRepository userRepository = beanFactory.getBean("userRepository", UserRepository.class);
  16. //「[User{id=1, name='Steve'}, SuperUser{address='北京'} User{id=1, name='Steve'}]」
  17. System.out.println(userRepository.getUsers());
  18. // 获取对象依赖注入,输出:「org.springframework.beans.factory.support.DefaultListableBeanFactory@57baeedf: defining beans
  19. // [user,superUser,objectFactoryCreatingFactoryBean,userRepository]; root of factory hierarchy」
  20. // 内建的依赖
  21. System.out.println(userRepository.getBeanFactory());
  22. // 对比以下代码:
  23. // 1. BeanFactory beanFactory
  24. // 2. ObjectFactory<User> userObjectFactory
  25. // 3. ObjectFactory<ApplicationContext>applicationContextObjectFactory
  26. // 输出:「false」
  27. System.out.println((userRepository.getBeanFactory() == beanFactory));
  28. // 依赖查找:报错「No qualifying bean of type 'org.springframework.beans.factory.BeanFactory' available」
  29. // 说明:BeanFactory.class 是内建的非 Bean 对象,内建的依赖
  30. // System.out.println(beanFactory.getBean(BeanFactory.class));
  31. // ObjectFactory<User> userObjectFactory <--> ObjectFactory<ApplicationContext>applicationContextObjectFactory
  32. ObjectFactory userObjectFactory = userRepository.getUserObjectFactory();
  33. // 输出 :「SuperUser{address='北京'} User{id=1, name='Steve'}」
  34. System.out.println(userObjectFactory.getObject());
  35. // 输出:「false」
  36. System.out.println(userObjectFactory.getObject() == beanFactory);
  37. ObjectFactory applicationContextObjectFactory = userRepository.getApplicationContextObjectFactory();
  38. // 输出:「org.springframework.context.support.ClassPathXmlApplicationContext@6f75e721, started on Thu Dec 23
  39. // 00:55:34 CST 2021」
  40. System.out.println(applicationContextObjectFactory.getObject());
  41. // 输出:「true」
  42. // 说明:ObjectFactory 自动注入的时候给我们注入了 ApplicationContext
  43. System.out.println(applicationContextObjectFactory.getObject() == beanFactory);
  44. // 对比结束
  45. // 容器内建 Bean,输出:「获取 Environment 类型的 Bean:StandardEnvironment {activeProfiles=[],……」
  46. Environment environment = beanFactory.getBean(Environment.class);
  47. System.out.println("获取 Environment 类型的 Bean:" + environment);
  48. }
  49. }

UserSuperUser@Super 见上节内容

Spring IoC 依赖来源

来源

主要有以下:

  1. 自定义 Bean -> 比如:业务上的 Bean 对象
  2. 容器内建 Bean 对象 -> 比如:Environment.class
  3. 容器内建依赖 -> 比如:BeanFactory.class

    代码

    参考:Spring IoC 依赖注入部分

    Spring IoC 配置元信息

  4. Bean 定义配置

    1. 基于 XML 文件
    2. 基于 Properties 文件
    3. 基于 Java 注解
    4. 基于 Java API
  5. IoC 容器配置
    1. 基于 XML 文件
    2. 基于 Java 注解
    3. 基于 Java API
  6. 外部化属性配置
    1. 基于 Java 注解

      Spring IoC 容器

      来看下 Spring 文档:

      The org.springframework.beans and org.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 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. For more information on using the BeanFactory instead of the ApplicationContext, see [BeanFactory](https://docs.spring.io/spring-framework/docs/5.2.12.RELEASE/spring-framework-reference/core.html#beans-beanfactory).

      —— Introduction to the Spring IoC Container and Beans

大概意思就是说 BeanFactory 是 ApplicationContext 的父接口,提供了基本功能,而后者添加了更多的企业性的特性:

  1. 更方便基础 Spring AOP 特性
  2. 国际化处理
  3. 事件发布
  4. 提供了特定的上下文

可以看下 UML 图验证:
image.png

简单来个结论:

  1. BeanFactory 是 Spring 底层的 IoC 容器
  2. 从功能上来说,ApplicationContext 是 BeanFactory 的超集
  3. 二者不是对等的

    Spring 应用上下文

    ApplicationContext 接口除了上述的「容器」的功能,还有以下功能:

  4. 面向切面(AOP)

  5. 配置元信息(Configuration Metadata)
  6. 资源管理(Resources)
  7. 事件(Events)
  8. 国际化(il8n)
  9. 注解(Annotations)
  10. Environment 抽象(Environment Abstraction)

    使用 Spring IoC 容器

    使用 BeanFactory

    此处的 DefaultListableBeanFactoryBeanFactory 的实现:
    image.png

    1. **
    2. * BeanFactory 作为 IoC 容器示例
    3. *
    4. * @author mindartisan.blog.csdn.net
    5. * @date
    6. */
    7. public class BeanFactoryAsIoCContainerDemo {
    8. public static void main(String[] args) {
    9. // 创建 BeanFactory 容器
    10. DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
    11. XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
    12. String location = "classpath:/META-INF/dependency-lookup-context.xml";
    13. // 加载配置
    14. int beanDefinitionsCount = reader.loadBeanDefinitions(location);
    15. System.out.println("Bean 定义加载的数量:"+beanDefinitionsCount);
    16. // 依赖查找集合对象
    17. // 简单说明不用 ApplicationContext 的时候也能加载 Bean
    18. lookupCollectionByType(defaultListableBeanFactory);
    19. }
    20. /**
    21. * 按类型查找:多个 bean
    22. *
    23. * @param beanFactory bean工厂
    24. */
    25. private static void lookupCollectionByType(BeanFactory beanFactory) {
    26. if (beanFactory instanceof ListableBeanFactory) {
    27. ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
    28. // key 为 bean 名称
    29. Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
    30. System.out.println("按类型查找,多个 bean:" + users);
    31. }
    32. }
    33. }

    使用 ApplicationContext

    此处的 AnnotationConfigApplicationContextApplicationContext 的实现:
    image.png ```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) {
        1. ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
        2. // key 为 bean 名称
        3. Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
        4. System.out.println("按类型查找,多个 bean:" + users);
        } } }
  1. <a name="NffWX"></a>
  2. # Spring IoC 容器生命周期
  3. <a name="cMnCL"></a>
  4. ## 启动
  5. <a name="G7Ilw"></a>
  6. ### AbstractApplicationContext#refresh()
  7. ```java
  8. public void refresh() throws BeansException, IllegalStateException {
  9. // 不知道当前用户的线程安全不安全
  10. synchronized (this.startupShutdownMonitor) {
  11. // Prepare this context for refreshing.
  12. // 准备阶段
  13. prepareRefresh();
  14. // Tell the subclass to refresh the internal bean factory.
  15. // 让子类去刷新内置的 BeanFactory,
  16. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  17. // Prepare the bean factory for use in this context.
  18. prepareBeanFactory(beanFactory);
  19. try {
  20. // Allows post-processing of the bean factory in context subclasses.
  21. // 加载 bean,但不实例化 bean:
  22. postProcessBeanFactory(beanFactory);
  23. // Invoke factory processors registered as beans in the context.
  24. // 调用在上下文中注册为 bean的 factory processor,BeanFactory 扩展点
  25. invokeBeanFactoryPostProcessors(beanFactory);
  26. // Register bean processors that intercept bean creation.
  27. // 实例化并注册所有 BeanPostProcessor bean,Bean 扩展
  28. registerBeanPostProcessors(beanFactory);
  29. // Initialize message source for this context.
  30. // 国际化
  31. initMessageSource();
  32. // Initialize event multicaster for this context.
  33. // 事件广播
  34. initApplicationEventMulticaster();
  35. // Initialize other special beans in specific context subclasses.
  36. // 初始化特定上下文的其他特殊 bean
  37. onRefresh();
  38. // Check for listener beans and register them.
  39. // 注册监听器
  40. registerListeners();
  41. // Instantiate all remaining (non-lazy-init) singletons.
  42. // 实例化所有的单例 bean
  43. finishBeanFactoryInitialization(beanFactory);
  44. // Last step: publish corresponding event.
  45. // 完成上下文刷新
  46. finishRefresh();
  47. }
  48. catch (BeansException ex) {
  49. if (logger.isWarnEnabled()) {
  50. logger.warn("Exception encountered during context initialization - " +
  51. "cancelling refresh attempt: " + ex);
  52. }
  53. // Destroy already created singletons to avoid dangling resources.
  54. // 有异常了销毁 bean
  55. destroyBeans();
  56. // Reset 'active' flag.
  57. cancelRefresh(ex);
  58. // Propagate exception to caller.
  59. throw ex;
  60. }
  61. finally {
  62. // Reset common introspection caches in Spring's core, since we
  63. // might not ever need metadata for singleton beans anymore...
  64. resetCommonCaches();
  65. }
  66. }
  67. }

AbstractApplicationContext#prepareRefresh()

  1. protected void prepareRefresh() {
  2. // Switch to active.
  3. // 记录启动时间,算运行时间
  4. this.startupDate = System.currentTimeMillis();
  5. this.closed.set(false);
  6. this.active.set(true);
  7. if (logger.isDebugEnabled()) {
  8. if (logger.isTraceEnabled()) {
  9. logger.trace("Refreshing " + this);
  10. }
  11. else {
  12. logger.debug("Refreshing " + getDisplayName());
  13. }
  14. }
  15. // 初始化 PropertySources
  16. // Initialize any placeholder property sources in the context environment.
  17. initPropertySources();
  18. // Validate that all properties marked as required are resolvable:
  19. // see ConfigurablePropertyResolver#setRequiredProperties
  20. // 校验需要的 Properties
  21. getEnvironment().validateRequiredProperties();
  22. // Store pre-refresh ApplicationListeners...
  23. if (this.earlyApplicationListeners == null) {
  24. this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
  25. }
  26. else {
  27. // Reset local application listeners to pre-refresh state.
  28. this.applicationListeners.clear();
  29. this.applicationListeners.addAll(this.earlyApplicationListeners);
  30. }
  31. // Allow for the collection of early ApplicationEvents,
  32. // to be published once the multicaster is available...
  33. this.earlyApplicationEvents = new LinkedHashSet<>();
  34. }

停止

AbstractApplicationContext#close()

  1. public void close() {
  2. synchronized (this.startupShutdownMonitor) {
  3. // 关闭
  4. doClose();
  5. // If we registered a JVM shutdown hook, we don't need it anymore now:
  6. // We've already explicitly closed the context.
  7. if (this.shutdownHook != null) {
  8. try {
  9. Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
  10. }
  11. catch (IllegalStateException ex) {
  12. // ignore - VM is already shutting down
  13. }
  14. }
  15. }
  16. }

AbstractApplicationContext#doClose()

  1. protected void doClose() {
  2. // Check whether an actual close attempt is necessary...
  3. if (this.active.get() && this.closed.compareAndSet(false, true)) {
  4. if (logger.isDebugEnabled()) {
  5. logger.debug("Closing " + this);
  6. }
  7. LiveBeansView.unregisterApplicationContext(this);
  8. try {
  9. // Publish shutdown event.
  10. publishEvent(new ContextClosedEvent(this));
  11. }
  12. catch (Throwable ex) {
  13. logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
  14. }
  15. // Stop all Lifecycle beans, to avoid delays during individual destruction.
  16. if (this.lifecycleProcessor != null) {
  17. try {
  18. this.lifecycleProcessor.onClose();
  19. }
  20. catch (Throwable ex) {
  21. logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
  22. }
  23. }
  24. // Destroy all cached singletons in the context's BeanFactory.
  25. // 销毁 bean
  26. destroyBeans();
  27. // Close the state of this context itself.
  28. // 关闭 BeanFactory
  29. closeBeanFactory();
  30. // Let subclasses do some final clean-up if they wish...
  31. onClose();
  32. // Reset local application listeners to pre-refresh state.
  33. if (this.earlyApplicationListeners != null) {
  34. this.applicationListeners.clear();
  35. this.applicationListeners.addAll(this.earlyApplicationListeners);
  36. }
  37. // Switch to inactive.
  38. this.active.set(false);
  39. }
  40. }