Spring Bean基础-4

1. 定义Bean: 什么是BeanDefinition?

  • 什么是BeanDefinition?
  • BeanDefinition 是 Spring Framework 中定义 Bean 的配置元信息接口, 包含:
    • Bean 的类名
    • Bean 行为配置元素, 如作用域、自动绑定的模式、生命周期回调等
    • 其他 Bean 引用, 又可称作合作者 (Collaborators) 或者依赖 (Dependencies)
    • 配置设置, 比如 Bean 属性 (Properties)

2. BeanDefinition元信息: 除了Bean名称和类名, 还有那些Bean元信息值的关注?

  • BeanDefinition 元信息

    属性 (Property) 说明
    Class Bean 全类名, 必须是具体类, 不能用抽象类或接口
    Name Bean 的名称或者 ID
    Scope Bean 的作用域 (如: singleton、prototype 等)
    Constructor arguments Bean 构造器参数 (用于依赖注入)
    Properties Bean 属性设置 (用于依赖注入)
    Autowiring mode Bean 自动绑定模式 (如: 通过名称 byName)
    Lazy initialization mode Bean 延迟初始化模式 (延迟和非延迟)
    initialization method Bean 初始化回调方法名称
    Destruction method Bean 销毁回调方法名称
  • BeanDefinition 构建

    • 通过 BeanDefinitionBuilder

    • 通过 AbstractBeanDefinition 以及派生类

      User.class

      package org.xiaoge.thinking.in.spring.ioc.overview.domain;
      
      /**
       * @Classname User
       * @Date 2022/10/17 14:57
       * @Created by ZhangXiao
       * @Description TODO
       */
      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 + '\'' +
                      '}';
          }
      }
      
      

      BeanDefinitionCreationDemo.class

      package org.xiaoge.thinking.in.spring.bean.definition;
      
      import org.springframework.beans.MutablePropertyValues;
      import org.springframework.beans.factory.config.BeanDefinition;
      import org.springframework.beans.factory.support.AbstractBeanDefinition;
      import org.springframework.beans.factory.support.BeanDefinitionBuilder;
      import org.springframework.beans.factory.support.GenericBeanDefinition;
      import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
      
      /**
       * {@link org.springframework.beans.factory.config.BeanDefinition} 构建示例
       *
       * @Classname BeanDefinitionCreationDemo
       * @Date 2022/11/2 16:05
       * @Created by ZhangXiao
       * @Description TODO
       */
      public class BeanDefinitionCreationDemo {
              
              
      
          public static void main(String[] args) {
              
              
              // 1. 通过 BeanDefinitionBuilder 构建
              BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
              // 通过属性设置
              beanDefinitionBuilder
                      .addPropertyValue("id", 1)
                      .addPropertyValue("name", "xiaoge");
              // 获取 BeanDefinition 实例
              BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
              // BeanDefinition 并非 Bean 终态, 可以自定义修改
      
      
              // 2. 通过 AbstractBeanDefinition 以及派生类
              GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
              // 设置 Bean 类型
              genericBeanDefinition.setBeanClass(User.class);
      
              // 通过 MutablePropertyValues 批量操作属性
              MutablePropertyValues propertyValues = new MutablePropertyValues();
              // propertyValues.addPropertyValue("id", 1);
              // propertyValues.addPropertyValue("name", "xiaoge");
              propertyValues
                      .add("id", 1)
                      .add("name", "xiaoge");
      
              // 通过 set MutablePropertyValues 批量操作属性
              genericBeanDefinition.setPropertyValues(propertyValues);
      
          }
      
      }
      

3. 命名Spring Bean: id和name属性命名Bean, 那个更好?

  • Bean名称

    • 每个Bean 拥有一个或多个标识符(identifiers) ,这些标识符在Bean 所在的容器必须是唯一的。通常,一个 Bean仅有一个标识符,如果需要额外的,可考虑使用别名(Alias) 来扩充。

    • 在基于XML的配置元信息中,开发人员可用id或者name属性来规定 Bean的标识符。通常Bean 的标识符由字母组成,允许出现特殊字符。如果要想引入 Bean 的别名的话,可在
      name 属性使用半角逗号(“,”)或分号(“;”)来间隔。

    • Bean 的id 或name属性并非必须制定,如果留空的话,容器会为Bean自动生成一个唯一的名称。Bean的命名尽管没有限制, 不过官方建议采用驼峰的方式,更符合Java的命名约定。

    • Bean名称生成器(BeanNameGenerator)

      扫描二维码关注公众号,回复: 15558140 查看本文章
    • 由Spring Framework 2.0.3引入,框架内建两种实现:

      • DefaultBeanNameGenerator:默认通用BeanNameGenerator 实现
    • AnnotationBeanNameGenerator:基于注解扫描的 BeanNameGenerator实现,
      起始于SpringFramework 2.5,关联的官方文档:

      With component scanning in the classpath,Spring generates bean names for unnamed components,following the rules described earlier: essentially,taking the simple class name and turnined components,following the rules described earlier: essentially,taking the simple class name and turning its initial character to lower-case.However, in the (unusual) special case when there is more than one character and both the first and second characters are upper case, the original casing gets preserved.These are the same rules as defined by java.beans.Introspector.decapitalize (which Spring uses herre).
      
      通过在类路径中扫描component,Spring为未命名的组件生成bean名称,遵循前面描述的规则:实质上,采用简单的类名和翻转的组件,遵循前面描述的规则:实质上,采用简单的类名并将其初始字符改为小写。但是,在(不寻常的)特殊情况下,当有多个字符并且第一个和第二个字符都是大写字母时,原始的大小写将被保留。这些规则与java.beans.Introspector.decapitalize (Spring在这里使用)定义的规则相同。
      

      关于Bean的命名, Bean的命名有两种方式, 一种是Spring容器自动帮你生成, 当你没有设置名称/id的时候, 另一种是自己去定义所需要的名称, 一般XML是自己定义名称, 而注解我们一般很少会自己去定义名称。

4. Spring Bean的别名: 为什么命名Bean 还需要别名?

  • Bean别名(Alias)的价值

    • 复用现有的 BeanDefinition

    • 更具有场景化的命名方法,比如:

      • Bean别名(Alias)的价值

        <alias name="myApp-dataSource" alias="subsystemA-dataSource" />
        <alias name="myApp-dataSource" alias="subsystemB-dataSource" />
        
      • bean-deginitions-context.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"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
                https://www.springframework.org/schema/beans/spring-beans.xsd">
        
            <!--    通过导入复用 dependency-lookup-context.xml -->
            <import resource="classpath:/META-INF/dependency-lookup-context.xml" />
        
            <!-- 讲 Spring 容器中 user bean 关联/建立别名 - xiaoge-user -->
            <alias name="user" alias="xiaoge-user"/>
        
        </beans>
        
      • BeanAliasDemo

        package org.xiaoge.thinking.in.spring.bean.definition;
        
        import org.springframework.beans.factory.BeanFactory;
        import org.springframework.context.support.ClassPathXmlApplicationContext;
        import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
        
        /**
         * {@link BeanAliasDemo} 别名示例
         *
         * @Classname BeanAliasDemo
         * @Date 2022/11/2 17:02
         * @Created by ZhangXiao
         * @Description TODO
         */
        public class BeanAliasDemo {
                  
                  
        
            public static void main(String[] args) {
                  
                  
                // 配置xml配置文件
                // 启动spring应用上下文
                BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-deginitions-context.xml");
        
                // 通过id和类型取
                User user = beanFactory.getBean("user", User.class);
        
                // 通过别名 获取 曾用命 user 的 Bean
                User xiaogeUser = beanFactory.getBean("xiaoge-user", User.class);
        
                System.out.println("xiaogeUser 是否与 user Bean 相同: " + (xiaogeUser == user));
        
            }
        
        }
        
        /*
        	运行结果
        		xiaogeUser 是否与 user Bean 相同: true
        */
        

5. 注册Spring Bean: 如何讲BeanDefinition注册到IoC容器?

  • BeanDefinition 注册

    • XML 配置元信息
      • <bean name="…”… />
    • Java 注解配置元信息
      • @Bean
      • @Component
      • @Import
    • Java API 配置元信息
      • 命名方式:BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
      • 非命名方式:BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition,BeandefinitionRegistry)
      • 配置类方式: AnnotatedBeanDefinitionReader#register(Class…)
  • XML这里就不写了, 主要写注解 和 JavaAPI 方式

    package org.xiaoge.thinking.in.spring.bean.definition;
    
    import org.springframework.beans.factory.support.AbstractBeanDefinition;
    import org.springframework.beans.factory.support.BeanDefinitionBuilder;
    import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Import;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
    
    /**
     *
     * 注解 BeanDefinition 示例
     *      1. 通过 @Bean 方式定义
     *      2. 通过 @Component 方式定义
     *      3. 通过 @Import 方式定义
     * Java API 配置元信息
     *      1. 通过 BeanDefinitionRegistry 方式定义
     *      2. 通过 BeanDefinitionReaderUtils 方式定义
     *      3. 通过 AnnotatedBeanDefinitionReader 方式定义
     *
     * @Classname AnnotationBeanDefinitionDemo
     * @Date 2022/11/3 9:22
     * @Created by ZhangXiao
     * @Description TODO
     */
    @Import(AnnotationBeanDefinitionDemo.Config.class) // 3. 通过 @Import 方式定义
    public class AnnotationBeanDefinitionDemo {
          
          
    
        public static void main(String[] args) {
          
          
            // 创建 ApplicationContext 容器
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    
            // 注册 Configuration Class 配置类
            applicationContext.register(AnnotationBeanDefinitionDemo.class);
    
            // 通过 BeanDefinition 注册 API 实现
            // 1. 命名 Bean 的注册方式
            registerUserBeanDefinition(applicationContext, "xiaoge-niubi");
            // 2. 非命名 Bean 的注册方式
            registerUserBeanDefinition(applicationContext);
            // 3. 配置类方式
            AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(applicationContext);
            annotatedBeanDefinitionReader.register(Config.class);
    
            // 启动应用上下文
            applicationContext.refresh();
    
            // 按照类型依赖查找
            System.out.println("Config 类型的所有 Beans: " + applicationContext.getBeansOfType(Config.class));
            System.out.println("User 类型的所有 Beans: " + applicationContext.getBeansOfType(User.class));
    
    
            // 关闭应用上下文
            applicationContext.close();
        }
    
    
        /**
         * 带名 注册到 ioc 容器
         * @param register
         * @param beanName
         */
        public static void registerUserBeanDefinition(BeanDefinitionRegistry register, String beanName) {
          
          
            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
            beanDefinitionBuilder
                    .addPropertyValue("id", 1)
                    .addPropertyValue("name", "xiaoge");
    
            // 构建 BeanDefinition
            AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
    
            // 判断如果beanName存在时
            if (StringUtils.isEmpty(beanName)) {
          
          
                // 注册 BeanDefinition  非命名方式(不带名称) 注册
                BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, register);
            } else {
          
          
                // 注册 BeanDefinition  命名方式(带名称) 注册
                register.registerBeanDefinition(beanName, beanDefinition);
            }
    
        }
    
        public static void registerUserBeanDefinition(BeanDefinitionRegistry register) {
          
          
            registerUserBeanDefinition(register,null);
        }
    
        // 定义当前类做为 Spring Bean (组件)
        @Component // 2. 通过 @Component 方式定义
        public static class Config {
          
          
            /**
             * 通过 Java 注解的方式, 定义了一个 Bean
             * @return
             */
            @Bean(name = {
          
          "user", "user-xiaoge"}) // 1. 通过 @Bean 方式定义
            public User user() {
          
          
                User user = new User();
                user.setId(1L);
                user.setName("xiaoge");
                return user;
            }
        }
    
    }
    
    
    
    /*
    	运行结果:
    		Config 类型的所有 Beans: {annotationBeanDefinitionDemo.Config=org.xiaoge.thinking.in.spring.bean.definition.AnnotationBeanDefinitionDemo$Config@fa4c865}
    		
    		User 类型的所有 Beans: {xiaoge-niubi=User{id=1, name='xiaoge'}, org.xiaoge.thinking.in.spring.ioc.overview.domain.User#0=User{id=1, name='xiaoge'}, user=User{id=1, name='xiaoge'}}
    
    */
    

6. 实例化Spring Bean: Bean实例化的姿势有多少种?

  • Bean实例化(Instantiation)

    • 常规方式:
      • 通过构造器(配置元信息: XML、Java 注解 和 Java APl )
      • 通过静态工厂方法(配置元信息: XML 和 Java API )
      • 通过Bean工厂方法(配置元信息: XML 和 Java APl )
      • 通过FactoryBean(配置元信息: XML、Java 注解 和 Java API )
    • 特殊方式:
      • 通过ServiceLoaderFactoryBean(配置元信息∶XML、Java注解 和 Java API )
      • 通过AutowireCapableBeanFactory#createBean(java.lang.Class, int, boolean)
      • 通过 BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
  • bean-instantiation-context.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- 静态方法实例化 Bean -->
        <bean id="user-by-static-method" class="org.xiaoge.thinking.in.spring.ioc.overview.domain.User" factory-method="createUser" />
    
    
        <!-- 实例 (Bean) 方式  实例化 Bean   factory-bean只想实例化的user工厂 -->
        <bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser" />
    
        <!-- FactoryBean(实例化) Bean -->
        <bean id="user-by-factory-bean" class="org.xiaoge.thinking.in.spring.bean.factory.UserFactoryBean" />
    
        <!-- 实例化bean -->
        <bean id="userFactory" class="org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory" />
    
    
    
    
    </beans>
    
  • special-bean-instantiation-context.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- serviceLoader它会关注所有的bean, 但是我这里设置了serviceType只关注一种bean -->
       <bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
           <property name="serviceType" value="org.xiaoge.thinking.in.spring.bean.factory.UserFactory"></property>
       </bean>
    
    </beans>
    
  • org.xiaoge.thinking.in.spring.bean.factory.UserFactory

    org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory
    org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory
    org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dlMENwbx-1669085413218)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121095520604.png)]

  • User.java

    package org.xiaoge.thinking.in.spring.ioc.overview.domain;
    
    /**
     * @Classname User
     * @Date 2022/10/17 14:57
     * @Created by ZhangXiao
     * @Description TODO
     */
    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 + '\'' +
                    '}';
        }
    
        public static User createUser() {
          
          
            User user = new User();
            user.setId(1L);
            user.setName("xiaoge");
            return user;
        }
    }
    
    
  • UserFactory.java

    package org.xiaoge.thinking.in.spring.bean.factory;
    
    import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
    
    /**
     *
     * {@link User} 工厂类
     *
     * @Classname DefaultUserFactory
     * @Date 2022/11/8 17:19
     * @Created by ZhangXiao
     * @Description
     */
    public interface UserFactory {
          
          
    
        default User createUser() {
          
          
            return User.createUser();
        }
    
    }
    
  • DefaultUserFactory.java

    package org.xiaoge.thinking.in.spring.bean.factory;
    
    /**
     * @Classname DefaultUserFactory
     * @Date 2022/11/8 17:23
     * @Created by ZhangXiao
     * @Description TODO
     */
    public class DefaultUserFactory implements UserFactory {
          
          
    }
    
    
  • UserFactoryBean.java

    package org.xiaoge.thinking.in.spring.bean.factory;
    
    import org.springframework.beans.factory.FactoryBean;
    import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
    
    /**
     * {@link User} Bean 的 {@link FactoryBean} 实现
     *
     * 用FactoryBean 相当于 又 实例化 又 初始化
     *
     * @Classname UserFactoryBean
     * @Date 2022/11/8 17:32
     * @Created by ZhangXiao
     * @Description TODO
     */
    public class UserFactoryBean implements FactoryBean {
          
          
    
        @Override
        public Object getObject() throws Exception {
          
          
            return User.createUser();
        }
    
    
        @Override
        public Class<?> getObjectType() {
          
          
            return User.class;
        }
    
    }
    
  • BeanInstantiationDemo.java

    package org.xiaoge.thinking.in.spring.bean.definition;
    
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
    
    /**
     * @Classname BeanInstantiationDemo
     * @Date 2022/11/8 17:15
     * @Created by ZhangXiao
     * @Description Bean 实例化  示例
     *
     * 实例化:是对象创建的过程。比如使用构造方法new对象,为对象在内存中分配空间。
     * 初始化:是为对象中的属性赋值的过程。
     *
     * 1. 通过构造器方法这里就不写了, 之前写过
     * 2. 通过静态工厂方法
     * 3. 通过Bean工厂方法
     * 4. 通过FactoryBean
     *
     */
    public class BeanInstantiationDemo {
          
          
    
        public static void main(String[] args) {
          
          
            // 配置xml配置文件
            // 启动spring应用上下文
            BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-instantiation-context.xml");
            // 1. 通过静态工厂方法
            User user = beanFactory.getBean("user-by-static-method", User.class);
            // 2. 通过Bean工厂方法
            User userByInstanceMethod = beanFactory.getBean("user-by-instance-method", User.class);
            // 3. 通过FactoryBean
            User userByFactoryBean = beanFactory.getBean("user-by-factory-bean", User.class);
            System.out.println(user);
            System.out.println(userByInstanceMethod);
            System.out.println(userByFactoryBean);
            System.out.println(user == userByInstanceMethod);
            System.out.println(user == userByFactoryBean);
        }
    
    }
    
    
    // 运行结果
    User{
          
          id=1, name='xiaoge'}
    User{
          
          id=1, name='xiaoge'}
    User{
          
          id=1, name='xiaoge'}
    false
    false
    
  • SpecialBeanInstantiationDemo.java

    package org.xiaoge.thinking.in.spring.bean.definition;
    
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory;
    import org.xiaoge.thinking.in.spring.bean.factory.UserFactory;
    
    import java.util.Iterator;
    import java.util.ServiceLoader;
    
    /**
     * 特殊的 Bean 实例化 示例
     *  1. ServiceLoaderFactoryBean
     *  2. AutowireCapableBeanFactory
     *  3. BeanDefinitionRegistry这里就不写了, 之前写过
     *
     *  实例化:是对象创建的过程。比如使用构造方法new对象,为对象在内存中分配空间。
     *  初始化:是为对象中的属性赋值的过程。
     *
     * @Classname SpecialBeanInstantiaionDemo
     * @Date 2022/11/8 17:42
     * @Created by ZhangXiao
     * @Description TODO
     */
    public class SpecialBeanInstantiationDemo {
          
          
    
        public static void main(String[] args) {
          
          
            // 配置xml配置文件
            // 启动spring应用上下文
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/special-bean-instantiation-context.xml");
    
            // 通过 ApplicationContext 获取 AutowireCapableBeanFactory
            AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
    
            ServiceLoader<UserFactory> userFactoryServiceLoader = beanFactory.getBean("userFactoryServiceLoader", ServiceLoader.class);
    
            displayServiceLoad(userFactoryServiceLoader);
    
            demoServiceLoader();
    
            // 创建 UserFactory 对象, 通过 AutowireCapableBeanFactory
            UserFactory userFactory = beanFactory.createBean(DefaultUserFactory.class);
            System.out.println(userFactory.createUser());
        }
    
    
        /**
         * 这种方式可以实例化多个bean, 默认去找META-INF/services
         * 而我们写的是三个同样的Bean 
         * org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory
    	 * org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory
    	 * org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory
         * 所以这里只会创建一个
         *
         */
        private static void demoServiceLoader() {
          
          
            ServiceLoader<UserFactory> serviceLoader = ServiceLoader.load(UserFactory.class, Thread.currentThread().getContextClassLoader());
            displayServiceLoad(serviceLoader);
        }
    
    
        /**
         * 这种方式只会找一个, 找我们关注的设置了serviceType的
         * @param serviceLoader
         */
        private static void displayServiceLoad(ServiceLoader<UserFactory> serviceLoader) {
          
          
    
            Iterator<UserFactory> iterator = serviceLoader.iterator();
            while(iterator.hasNext()) {
          
          
                UserFactory userFactory = iterator.next();
                System.out.println(userFactory.createUser());
            }
    
        }
    
    
    }
    
    
    // 运行结果
    User{
          
          id=1, name='xiaoge'}
    User{
          
          id=1, name='xiaoge'}
    User{
          
          id=1, name='xiaoge'}
    

7. 初始化Spring Bean: Bean初始化有那些方式?

  • Bean初始化(Initialization)

    • @PostConstruct 标注方法
    • 实现 InitializingBean 接口的 afterPropertiesSet() 方法
    • 自定义初始化方法
      • XML 配置: <bean init-method="init”…/>
      • Java 注解: @Bean(initMethod=”init”)
      • Java API: AbstractBeanDefinition#setlnitMethodName(String)
    • 问题: 假设以上三种方式在同一 Bean 中定义, 那么这些方法的执行顺序是怎样?
      1. @PostConstruct
      2. InitializingBean 接口的 afterPropertiesSet() 方法
      3. 自定义初始化方法
  • User.java

    package org.xiaoge.thinking.in.spring.ioc.overview.domain;
    
    /**
     * @Classname User
     * @Date 2022/10/17 14:57
     * @Created by ZhangXiao
     * @Description TODO
     */
    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 + '\'' +
                    '}';
        }
    
        public static User createUser() {
          
          
            User user = new User();
            user.setId(1L);
            user.setName("xiaoge");
            return user;
        }
    }
    
  • UserFactory.java

    package org.xiaoge.thinking.in.spring.bean.factory;
    
    import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
    
    /**
     *
     * {@link User} 工厂类
     *
     * @Classname DefaultUserFactory
     * @Date 2022/11/8 17:19
     * @Created by ZhangXiao
     * @Description
     */
    public interface UserFactory {
          
          
    
        default User createUser() {
          
          
            return User.createUser();
        }
    
    }
    
    
  • DefaultUserFactory.java

    package org.xiaoge.thinking.in.spring.bean.factory;
    
    import org.springframework.beans.factory.InitializingBean;
    
    import javax.annotation.PostConstruct;
    
    /**
     * @Classname DefaultUserFactory
     * @Date 2022/11/8 17:23
     * @Created by ZhangXiao
     * @Description TODO
     */
    public class DefaultUserFactory implements UserFactory, InitializingBean {
          
          
    
        // 基于 @PostConstruct 注解
        @PostConstruct
        public void init() {
          
          
            System.out.println("@PostConstruct : UserFactory 初始化中.....");
        }
    
        public void initUserFactory() {
          
          
            System.out.println("自定义初始化方法 initUserFactory() : UserFactory 初始化中.....");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
          
          
            System.out.println("InitializingBean#afterPropertiesSet() : UserFactory 初始化中.....");
        }
    }
    
  • BeanInitializationDemo.java

    package org.xiaoge.thinking.in.spring.bean.definition;
    
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory;
    import org.xiaoge.thinking.in.spring.bean.factory.UserFactory;
    
    /**
     * @PACKAGE_NAME: org.xiaoge.thinking.in.spring.bean.definition
     * @Classname BeanInitializationDemo
     * @Date 2022/11/21 10:26
     * @Author zhangxiao
     * @Description Bean 初始化 示例
     *
     * 实例化:是对象创建的过程。比如使用构造方法new对象,为对象在内存中分配空间。
     * 初始化:是为对象中的属性赋值的过程。
     *
     * 1. @PostConstruct 标注方法
     * 2. InitializingBean 接口
     * 3. 自定义方法
     *    1. xml 这里就不说了
     *    2. @Bean 初始化 方法
     *    3. AbstractBeanDefinition#setlnitMethodName(String) 初始化方法
     */
    @Configuration
    public class BeanInitializationDemo {
          
          
    
        public static void main(String[] args) {
          
          
            // 1. 创建 ApplicationContext 容器
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    
            // 2. 注册 Configuration Class 配置类
            applicationContext.register(BeanInitializationDemo.class);
    
            // 3. 开启 spring 应用上下文
            applicationContext.refresh();
    
            // 4. 依赖查找
            applicationContext.getBean(UserFactory.class);
    
            // 5. 关闭 spring 应用上下文
            applicationContext.close();
        }
    
        @Bean(initMethod  = "initUserFactory")
        public UserFactory userFactory(){
          
          
            return new DefaultUserFactory();
        }
    
    }
    
    
    // 运行结果
    @PostConstruct : UserFactory 初始化中.....
    InitializingBean#afterPropertiesSet : UserFactory 初始化中.....
    自定义初始化方法 initUserFactory() : UserFactory 初始化中.....
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-75VFpexr-1669085413219)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121104247595.png)]

8. 延迟初始化 Spring Bean: 延迟初始化的 Bean 会影响依赖注入吗

  • Bean 延迟初始化 (Lazy Initialization)

    • XML配置: <bean lazy-init=”true"…/>
    • Java 注解: @Lazy(true)
  • 问题: 当某个Bean定义为延迟初始化,那么,Spring容器返回的对象与非延迟的对象存在怎样的差异?

    1. 延迟加载和非延迟加载在Bean定义的时候, 也就是Bean注册的时候是没有区别的, 按照你的需要来进行注册, 但是在依赖查找和依赖注入的时候它的区别就体现出来了。
    2. 非延迟查找实在上下文启动之前就已经初始化了。
    3. 延迟加载就必须是在初始化完成之后来进行加载 。
  • User.class

    package org.xiaoge.thinking.in.spring.ioc.overview.domain;
    
    /**
     * @Classname User
     * @Date 2022/10/17 14:57
     * @Created by ZhangXiao
     * @Description TODO
     */
    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 + '\'' +
                    '}';
        }
    
        public static User createUser() {
          
          
            User user = new User();
            user.setId(1L);
            user.setName("xiaoge");
            return user;
        }
    }
    
  • UserFactory.class

    package org.xiaoge.thinking.in.spring.bean.factory;
    
    import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
    
    /**
     *
     * {@link User} 工厂类
     *
     * @Classname DefaultUserFactory
     * @Date 2022/11/8 17:19
     * @Created by ZhangXiao
     * @Description
     */
    public interface UserFactory {
          
          
    
        default User createUser() {
          
          
            return User.createUser();
        }
    
    }
    
    
  • DefaultUserFactory.java

    package org.xiaoge.thinking.in.spring.bean.factory;
    
    import org.springframework.beans.factory.InitializingBean;
    
    import javax.annotation.PostConstruct;
    
    /**
     * @Classname DefaultUserFactory
     * @Date 2022/11/8 17:23
     * @Created by ZhangXiao
     * @Description TODO
     */
    public class DefaultUserFactory implements UserFactory, InitializingBean {
          
          
    
        // 基于 @PostConstruct 注解
        @PostConstruct
        public void init() {
          
          
            System.out.println("@PostConstruct : UserFactory 初始化中.....");
        }
    
        public void initUserFactory() {
          
          
            System.out.println("自定义初始化方法 initUserFactory() : UserFactory 初始化中.....");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
          
          
            System.out.println("InitializingBean#afterPropertiesSet() : UserFactory 初始化中.....");
        }
    }
    
  • BeanInitializationDemo

    package org.xiaoge.thinking.in.spring.bean.definition;
    
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Lazy;
    import org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory;
    import org.xiaoge.thinking.in.spring.bean.factory.UserFactory;
    
    /**
     * @PACKAGE_NAME: org.xiaoge.thinking.in.spring.bean.definition
     * @Classname BeanInitializationDemo
     * @Date 2022/11/21 10:26
     * @Author zhangxiao
     * @Description Bean 初始化 示例
     *
     * 实例化:是对象创建的过程。比如使用构造方法new对象,为对象在内存中分配空间。
     * 初始化:是为对象中的属性赋值的过程。
     *
     * 1. Lazy 延迟加载
     * 2. 非延迟加载
     */
    @Configuration
    public class BeanInitializationDemo {
          
          
    
        public static void main(String[] args) {
          
          
            // 1. 创建 ApplicationContext 容器
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    
            // 2. 注册 Configuration Class 配置类
            applicationContext.register(BeanInitializationDemo.class);
    
            // 3. 开启 spring 应用上下文
            applicationContext.refresh();
    
            // 4. 非延迟初始化在 Spring 应用上下文启动完成后, 被初始化
            System.out.println("Spring 应用上下文已启动...");
    
            // 4. 依赖查找
            UserFactory userFactory = applicationContext.getBean(UserFactory.class);
            System.out.println(userFactory);
    
            // 5. 关闭 spring 应用上下文
            applicationContext.close();
        }
    
        @Bean(initMethod  = "initUserFactory")
        @Lazy // 延迟加载
        //@Lazy(value = false) // 非延迟加载
        public UserFactory userFactory(){
          
          
            return new DefaultUserFactory();
        }
    
    }
    
    
    // 延迟加载
    Spring 应用上下文已启动...
    @PostConstruct : UserFactory 初始化中.....
    InitializingBean#afterPropertiesSet : UserFactory 初始化中.....
    自定义初始化方法 initUserFactory() : UserFactory 初始化中.....
    org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory@38364841
    
    // 非延迟加载
    @PostConstruct : UserFactory 初始化中.....
    InitializingBean#afterPropertiesSet : UserFactory 初始化中.....
    自定义初始化方法 initUserFactory() : UserFactory 初始化中.....
    Spring 应用上下文已启动...
    org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory@49070868
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tj0gVxyP-1669085413219)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121120058476.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z3G3mslL-1669085413220)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121120114370.png)]

    实例化或者说初始化所有剩余非延迟加载的Bean

9. 销毁Spring Bean: 销毁 Bean 的基本操作有那些?

  • Bean销毁(Destroy)

    • @PreDestroy标注方法
    • 实现DisposableBean接口的destroy()方法
    • 自定义销毁方法
      • XML配置:<bean destroy=“destroy”…/>
      • Java注解:@Bean(destroy=“destroy”)
      • Java API: AbstractBeanDefinition#setDestroyMethodName(String)
  • 问题: 假设以上三种方式均在同一 Bean 中定义, 那么这些方法的执行顺序是怎样?

    1. @PreDestroy
    2. DisposableBean接口的destroy()方法
    3. 自定义
  • User.java

    package org.xiaoge.thinking.in.spring.ioc.overview.domain;
    
    /**
     * @Classname User
     * @Date 2022/10/17 14:57
     * @Created by ZhangXiao
     * @Description TODO
     */
    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 + '\'' +
                    '}';
        }
    
        public static User createUser() {
          
          
            User user = new User();
            user.setId(1L);
            user.setName("xiaoge");
            return user;
        }
    }
    
  • UserFactory.java

    package org.xiaoge.thinking.in.spring.bean.factory;
    
    import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
    
    /**
     *
     * {@link User} 工厂类
     *
     * @Classname DefaultUserFactory
     * @Date 2022/11/8 17:19
     * @Created by ZhangXiao
     * @Description
     */
    public interface UserFactory {
          
          
    
        default User createUser() {
          
          
            return User.createUser();
        }
    
    }
    
    
  • DefaultUserFactory.java

    package org.xiaoge.thinking.in.spring.bean.factory;
    
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    /**
     * @Classname DefaultUserFactory
     * @Date 2022/11/8 17:23
     * @Created by ZhangXiao
     * @Description TODO
     */
    public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {
          
          
    
        // 基于 @PostConstruct 注解
        @PostConstruct
        public void init() {
          
          
            System.out.println("@PostConstruct : UserFactory 初始化中.....");
        }
    
        public void initUserFactory() {
          
          
            System.out.println("自定义初始化方法 initUserFactory() : UserFactory 初始化中.....");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
          
          
            System.out.println("InitializingBean#afterPropertiesSet() : UserFactory 初始化中.....");
        }
    
        // 基于 @PreDestroy 注解
        @PreDestroy
        public void preDestroy() {
          
          
            System.out.println("@PreDestroy : UserFactory 销毁中.....");
        }
    
        public void doDestroy() {
          
          
            System.out.println("自定义销毁方法 doDestroy() : UserFactory 销毁中.....");
        }
    
    
        @Override
        public void destroy() throws Exception {
          
          
            System.out.println("DisposableBean#destroy() : UserFactory 销毁中.....");
        }
    }
    
    
  • BeanInitializationDemo.java

    package org.xiaoge.thinking.in.spring.bean.definition;
    
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Lazy;
    import org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory;
    import org.xiaoge.thinking.in.spring.bean.factory.UserFactory;
    
    /**
     * @PACKAGE_NAME: org.xiaoge.thinking.in.spring.bean.definition
     * @Classname BeanInitializationDemo
     * @Date 2022/11/21 10:26
     * @Author zhangxiao
     * @Description Bean 初始化 示例
     *
     * 实例化:是对象创建的过程。比如使用构造方法new对象,为对象在内存中分配空间。
     * 初始化:是为对象中的属性赋值的过程。
     *
     * 1. @PreDestroy标注方法
     * 2. 实现DisposableBean接口的destroy()方法
     * 3. 自定义方法
     */
    @Configuration
    public class BeanInitializationDemo {
          
          
    
        public static void main(String[] args) {
          
          
            // 1. 创建 ApplicationContext 容器
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    
            // 2. 注册 Configuration Class 配置类
            applicationContext.register(BeanInitializationDemo.class);
    
            // 3. 开启 spring 应用上下文
            applicationContext.refresh();
    
            // 4. 非延迟初始化在 Spring 应用上下文启动完成后, 被初始化
            System.out.println("Spring 应用上下文已启动...");
    
            // 5. 依赖查找
            UserFactory userFactory = applicationContext.getBean(UserFactory.class);
            System.out.println(userFactory);
            System.out.println("Spring 应用上下文准备关闭...");
    
            // 6. 关闭 spring 应用上下文
            applicationContext.close();
    
            System.out.println("Spring 应用上下文已关闭...");
        }
    
        @Bean(initMethod  = "initUserFactory", destroyMethod = "doDestroy")
        @Lazy(value = false)
        public UserFactory userFactory(){
          
          
            return new DefaultUserFactory();
        }
    
    }
    
    
    // 运行结果
    @PostConstruct : UserFactory 初始化中.....
    InitializingBean#afterPropertiesSet() : UserFactory 初始化中.....
    自定义初始化方法 initUserFactory() : UserFactory 初始化中.....
    Spring 应用上下文已启动...
    org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory@38364841
    Spring 应用上下文准备关闭...
    @PreDestroy : UserFactory 销毁中.....
    DisposableBean#destroy() : UserFactory 销毁中.....
    自定义销毁方法 doDestroy() : UserFactory 销毁中.....
    Spring 应用上下文已关闭...
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vBaNcyBa-1669085413220)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121134545326.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i764VD1N-1669085413220)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121134625003.png)]

    销毁所有的BeanFactory

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YMX5tULm-1669085413220)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121134647783.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nYta5tot-1669085413221)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121134717379.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pZ42AeQB-1669085413221)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121134807191.png)]

    这里会做一个统计, 统计有多少个Bean实现了destroy方法, 它会足一的去进行销毁

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ALghvDW0-1669085413221)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121135007338.png)]

    这里会强制转换成DisposableBean

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xMJlrFSU-1669085413221)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121135117318.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FzxPISE4-1669085413222)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121135132801.png)]

    然后去掉它的destroy方法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-INT5vlbl-1669085413222)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121135223785.png)]

    因为这个方法被DisposableBean接口声明了

    @PreDestroy实现方式

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tDMrBaSS-1669085413222)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121135636968.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EO1ZyUkg-1669085413223)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121135718402.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KagJDBOd-1669085413223)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121135733015.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ahvGqDR-1669085413223)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121135745354.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R1HUhcQu-1669085413224)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121135824664.png)]

​ 剩下的跟上面一样, @PostConstruct也是这么初始化的

10.回收 Spring Bean: Spring IoC 容器管理的Bean能够被垃圾回收吗?

  • Bean垃圾回收(GC)

    1. 关闭Spring容器〈应用上下文)

    2. 执行GC

    3. Spring Bean覆盖的finalize()方法被回调

    4. 完成以上三步

  • DefaultUserFactory.java

    package org.xiaoge.thinking.in.spring.bean.factory;
    
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    /**
     * @Classname DefaultUserFactory
     * @Date 2022/11/8 17:23
     * @Created by ZhangXiao
     * @Description TODO
     */
    public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {
          
          
    
        // 基于 @PostConstruct 注解
        @PostConstruct
        public void init() {
          
          
            System.out.println("@PostConstruct : UserFactory 初始化中.....");
        }
    
        public void initUserFactory() {
          
          
            System.out.println("自定义初始化方法 initUserFactory() : UserFactory 初始化中.....");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
          
          
            System.out.println("InitializingBean#afterPropertiesSet() : UserFactory 初始化中.....");
        }
    
        // 基于 @PreDestroy 注解
        @PreDestroy
        public void preDestroy() {
          
          
            System.out.println("@PreDestroy : UserFactory 销毁中.....");
        }
    
        public void doDestroy() {
          
          
            System.out.println("自定义销毁方法 doDestroy() : UserFactory 销毁中.....");
        }
    
    
        @Override
        public void destroy() throws Exception {
          
          
            System.out.println("DisposableBean#destroy() : UserFactory 销毁中.....");
        }
    
        @Override
        public void finalize() throws Throwable {
          
          
            System.out.println("当前 DefaultUserFactory 对象正在被垃圾回收.....");
        }
    }
    
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yEtLYMU8-1669085413224)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121165623791.png)]

  • BeanGarbageCollectionDemo.java

    package org.xiaoge.thinking.in.spring.bean.definition;
    
    import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.xiaoge.thinking.in.spring.bean.factory.UserFactory;
    import org.xiaoge.thinking.in.spring.ioc.overview.domain.User;
    
    /**
     * @PACKAGE_NAME: org.xiaoge.thinking.in.spring.bean.definition
     * @Classname BeanGarbageCollectionDemo
     * @Date 2022/11/21 16:46
     * @Author zhangxiao
     * @Description TODO
     */
    public class BeanGarbageCollectionDemo {
          
          
    
        public static void main(String[] args) throws InterruptedException {
          
          
            // 1. 创建 ApplicationContext 容器
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    
            // 2. 注册 Configuration Class 配置类
            applicationContext.register(BeanInitializationDemo.class);
    
            // 3. 开启 spring 应用上下文
            applicationContext.refresh();
    
            // 4. 关闭 spring 应用上下文
            applicationContext.close();
    
            System.out.println("Spring 应用上下文已关闭...");
    
            Thread.sleep(5000);
    
            // 强制执行GC  finalize方法不一定完全被回调, 这个不是必须的, 只是模拟, spring容器中的Bean怎么被回收的
            System.gc();
    
            Thread.sleep(5000);
        }
    
    }
    
    
    // 运行结果
    @PostConstruct : UserFactory 初始化中.....
    InitializingBean#afterPropertiesSet() : UserFactory 初始化中.....
    自定义初始化方法 initUserFactory() : UserFactory 初始化中.....
    @PreDestroy : UserFactory 销毁中.....
    DisposableBean#destroy() : UserFactory 销毁中.....
    自定义销毁方法 doDestroy() : UserFactory 销毁中.....
    Spring 应用上下文已关闭...
    当前 DefaultUserFactory 对象正在被垃圾回收.....
    

11. 面试题精选

  • 如何注册一个 Spring Bean?

    • 答: 通过BeanDefinition和外部单体对象来注册

    • BeanDefinition这里不做例子上面有, 外部单体对象注册如下:

      • SingletonBeanRegistrationDemo.java

        package org.xiaoge.thinking.in.spring.bean.definition;
        
        import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
        import org.springframework.context.annotation.AnnotationConfigApplicationContext;
        import org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory;
        import org.xiaoge.thinking.in.spring.bean.factory.UserFactory;
        
        /**
         * @PACKAGE_NAME: org.xiaoge.thinking.in.spring.bean.definition
         * @Classname SingletonBeanRegistrationDemo
         * @Date 2022/11/21 17:39
         * @Author zhangxiao
         * @Description TODO
         */
        public class SingletonBeanRegistrationDemo {
                  
                  
        
            public static void main(String[] args) {
                  
                  
                // 创建 ApplicationContext 容器
                AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        
                // 创建一个外部 UserFactory 对象
                UserFactory userFactory = new DefaultUserFactory();
                ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
        
                // 注册外部单例 bean
                beanFactory.registerSingleton("userFactory", userFactory);
        
                // 开启 spring 应用上下文
                applicationContext.refresh();
        
                // 通过依赖查找的方式来获取 UserFactory
                UserFactory userFactoryByLookup = beanFactory.getBean("userFactory", UserFactory.class);
                System.out.println("userFactory == userFactoryByLookup : " + (userFactory == userFactoryByLookup));
        
                // 关闭 spring 应用上下文
                applicationContext.close();
            }
        
        }
        
        
        // 运行结果
        userFactory == userFactoryByLookup : true
        

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b2b4pySD-1669085413224)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121174819670.png)]

      • SingletonBeanRegistrationDemo.java

        package org.xiaoge.thinking.in.spring.bean.definition;
        
        import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
        import org.springframework.beans.factory.config.SingletonBeanRegistry;
        import org.springframework.context.annotation.AnnotationConfigApplicationContext;
        import org.xiaoge.thinking.in.spring.bean.factory.DefaultUserFactory;
        import org.xiaoge.thinking.in.spring.bean.factory.UserFactory;
        
        /**
         * @PACKAGE_NAME: org.xiaoge.thinking.in.spring.bean.definition
         * @Classname SingletonBeanRegistrationDemo
         * @Date 2022/11/21 17:39
         * @Author zhangxiao
         * @Description TODO
         */
        public class SingletonBeanRegistrationDemo {
                  
                  
        
            public static void main(String[] args) {
                  
                  
                // 创建 ApplicationContext 容器
                AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        
                // 创建一个外部 UserFactory 对象
                UserFactory userFactory = new DefaultUserFactory();
                SingletonBeanRegistry singletonBeanRegistry = applicationContext.getBeanFactory();
        
                // 注册外部单例 bean
                singletonBeanRegistry.registerSingleton("userFactory", userFactory);
        
                // 开启 spring 应用上下文
                applicationContext.refresh();
        
                // 通过依赖查找的方式来获取 UserFactory
                UserFactory userFactoryByLookup = applicationContext.getBean("userFactory", UserFactory.class);
                System.out.println("userFactory == userFactoryByLookup : " + (userFactory == userFactoryByLookup));
        
                // 关闭 spring 应用上下文
                applicationContext.close();
            }
        
        }
        
        
        // 运行结果
        userFactory == userFactoryByLookup : true
        

        为什么可以用applicationContext取到? 因为它是委派来实现的它是通过获取BeanFactory来获取bean

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kkzM7Z8x-1669085413225)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121175252470.png)]

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HrIFaSMe-1669085413225)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221121175317093.png)]

  • 什么是 Spring BeanDefinition?

    • BeanDefinition它实际上是一个关于Bean的定义的元信息, 这个接口可以允许我们存储, 就允许我们getter/setter的方式来来进行这个操作, 我们之前在xml中配置的那些东西, 其实就是是在实现接口中的方法, 例如:

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nRWWTujc-1669085413225)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221122102642164.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lfXQF6rh-1669085413225)(C:\Users\13301\AppData\Roaming\Typora\typora-user-images\image-20221122102702877.png)]

      等这里就不一一列举了

  • Spring容器是怎样管理注册 Bean

    • 如:loC配置元信息读取和解析、依赖查找和注入以及 Bean生命周期等。

猜你喜欢

转载自blog.csdn.net/zsx1314lovezyf/article/details/127978491