Spring Bean基础-4

news2024/7/4 6:03:50

1. 定义Bean: 什么是BeanDefinition?

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

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

  • BeanDefinition 元信息

    属性 (Property)说明
    ClassBean 全类名, 必须是具体类, 不能用抽象类或接口
    NameBean 的名称或者 ID
    ScopeBean 的作用域 (如: singleton、prototype 等)
    Constructor argumentsBean 构造器参数 (用于依赖注入)
    PropertiesBean 属性设置 (用于依赖注入)
    Autowiring modeBean 自动绑定模式 (如: 通过名称 byName)
    Lazy initialization modeBean 延迟初始化模式 (延迟和非延迟)
    initialization methodBean 初始化回调方法名称
    Destruction methodBean 销毁回调方法名称
  • 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)

    • 由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生命周期等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/25967.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Feign的简介及使用

一、Feign简介 Feign是一个声明式的http客户端&#xff0c;官方地址:https://github.com/OpenFeign/feign 其作用就是帮助我们优雅的实现http请求的发送&#xff0c;解决代码可读性差&#xff0c;编程体验不统一、参数复杂URL难以维护的问题。 二、使用Feign的步骤 1.引入依赖…

网络原理(Java网络编程)

1.局域网和广域网 局域网LAN: 即 Local Area Network,简称LAN. 局域网内的主机之间能方便的进行网络通信,又称为内网;局域网和局域网之间在没有连接的情况下,是无法通信的.局域网一般可以由交换机或路由器组建. 广域网WAN: 即 Wide Area Network,简称WAN. 广域网是将多个局域网…

【28-业务开发-基础业务-属性管理-SKU和SPU基本概念-SKU和SPU关联关系-属性实体之间的关联关系-批量菜单创建】

一.知识回顾 【0.三高商城系统的专题专栏都帮你整理好了&#xff0c;请点击这里&#xff01;】 【1-系统架构演进过程】 【2-微服务系统架构需求】 【3-高性能、高并发、高可用的三高商城系统项目介绍】 【4-Linux云服务器上安装Docker】 【5-Docker安装部署MySQL和Redis服务】…

力扣(LeetCode)32. 最长有效括号(C++)

栈模拟 合法的括号序列满足两条性质&#xff1a; 1.左括号数等于右括号数 2.任意前缀里&#xff0c;左括号数大于等于右括号数。 括号匹配和栈很般配&#xff0c;遇到左括号&#xff0c;下标入栈&#xff0c;遇到右括号&#xff0c;弹栈匹配。 这题的前缀里有两种不合法&…

【LSTM回归预测】attention机制LSTM时间序列回归预测【含Matlab源码 1992期】

⛄一、attention机制LSTM预测 1 总体框架 数字货币预测模型分为两部分&#xff0c;由LSTM模块和Attention模块组成。 2 LSTM模块 长短期记忆网络&#xff08;LSTM&#xff09;是一种特殊的递归神经网络&#xff08;RNN&#xff09;模型&#xff0c;是为了解决RNN模型梯度消失…

【Codeforces Round #835 (Div. 4)】A——G题解

文章目录A Medium Number题意思路代码B Atillas Favorite Problem题意思路代码C Advantage题意思路代码D Challenging Valleys题意思路代码E Binary Inversions题意思路代码F Quests题意思路代码G SlavicGs Favorite Problem题意思路代码A Medium Number 题意 三个数&#xf…

窗口-视口转换(详细)

在QPainter中&#xff0c;绘制图像使用逻辑坐标绘制&#xff0c;然后再转化为绘图设备的物理坐标。 窗口&#xff08;window&#xff09;&#xff1a;表示逻辑坐标下的相同矩形视口&#xff08;viewport&#xff09;&#xff1a;表示物理坐标下的指定的一个任意矩形默认情况&am…

中国互联网大会天翼云展区大揭秘!

11月15日&#xff0c;由工业和信息化部、深圳市人民政府主办&#xff0c;中国互联网协会、广东省通信管理局、深圳市工业和信息化局等单位承办的2022&#xff08;第二十一届&#xff09;中国互联网大会在深圳开幕。本届大会以“发展数字经济 促进数字文明”为主题&#xff0c;聚…

单商户商城系统功能拆解34—应用中心—分销应用

单商户商城系统&#xff0c;也称为B2C自营电商模式单店商城系统。可以快速帮助个人、机构和企业搭建自己的私域交易线上商城。 单商户商城系统完美契合私域流量变现闭环交易使用。通常拥有丰富的营销玩法&#xff0c;例如拼团&#xff0c;秒杀&#xff0c;砍价&#xff0c;包邮…

在IDEA中搭建Spring5.2.x版本源码(~附带完整过程和图示~)

1.开发环境 JDK8IntelliJ IDEA 2019.1.4 gradle 5.6.4git 2.33.0 2.操作步骤 下载并安装git 进入https://git-scm.com/downloads&#xff0c;下载对应操作系统的git版本一直点击next安装即可记得配置环境变量 获取Spring源码 使用clone的方式将源码拉取到本地&#xff0c;方便…

Java递归查询树形结构(详解)

一.数据准备 数据库表结构如下所示&#xff0c; INSERT INTO jg_user.com_type(type_id, parent_id, type_name) VALUES (1, 0, 合伙企业); INSERT INTO jg_user.com_type(type_id, parent_id, type_name) VALUES (2, 0, 有限公司); INSERT INTO jg_user.com_type(type_id, p…

力扣(LeetCode)878. 第 N 个神奇数字(C++)

二分查找数论 数论知识——辗转相除法、容斥原理。 辗转相除求最大公约数&#xff0c;两数相乘除以最大公约数&#xff0c;就是最小公倍数。 容斥原理求最多不重复元素&#xff0c;最大不重复面积。 <小学数奥> 从数据范围里&#xff0c;用容斥原理找 a/ba/ba/b 的倍数个…

Pytorch 下 TensorboardX 使用

这里引用一下在其他地方看到的一些话&#xff1a; tensorboard做为Tensorflow中强大的可视化工具&#xff0c;已经被普遍使用。 但针对其余框架&#xff0c;例如Pytorch&#xff0c;以前一直没有这么好的可视化工具可用&#xff0c;PyTorch框架自己的可视化工具是Visdom&…

实验九 数据微积分与方程数值求解(matlab)

实验九 数据微积分与方程数值求解 1.1实验目的 1.2实验内容 1.3流程图 1.4程序清单 1.5运行结果及分析 1.6实验的收获与体会 1.1实验目的 1&#xff0c;掌握求数值导数和数值积分的方法&#xff1b; 2&#xff0c;掌握代数方程数组求解的方法&#xff1b; 3&a…

【Mysql】Centos 7.6安装Mysql8

这里centos为阿里云默认镜像。 一、卸载历史历史版本 1、检查是否有服务启动 # service mysqld status 2、停止mysql服务 # service mysqld stop 3、查看mysql历史安装组件 # rpm -qa|grep mysqlmysql-libs-5.1.71-1.el6.x86_64 4、卸载组件 # rpm -e --nodeps mysql…

2022世界VR产业大会圆满收官,酷雷曼惊艳亮相!

11月14日&#xff0c;由工业和信息化部、江西省人民政府联合主办的全球VR领域规模最大、规格最高、影响最广的年度盛会——2022世界VR产业大会在江西南昌圆满落下帷幕。 本次大会得到了党中央、国务院的高度重视&#xff0c;国务委员王勇出席大会开幕式并讲话&#xff1b;大会邀…

【转】DNS隧道检测特征

原文链接&#xff1a;DNS隧道检测特征总结 - 知乎 一、摘要 企业内网环境中&#xff0c;DNS协议是必不可少的网络通信协议之一&#xff0c;为了访问互联网和内网资源&#xff0c;DNS提供域名解析服务&#xff0c;将域名和IP地址进行转换。网络设备和边界防护设备在一般的情况…

C++:内存管理:C++内存管理详解

C语言内存管理是指&#xff1a;对系统的分配、创建、使用这一系列操作。在内存管理中&#xff0c;由于是操作系统内存&#xff0c;使用不当会造成很麻烦的后果。本文将从系统内存的分配、创建出发&#xff0c;并且结合例子来说明内存管理不当会造成的结果以及解决方案。 一&am…

【Spring】Spring AOP的实现原理

目录 什么是AOP AOP的作用 AOP的优点 AOP框架 Spring AOP AspectJ 术语 1.Target ——目标类 2.Joinpoint ——连接点 3.Pointcut——切入点 4.Advice——通知/增强 5.Weaving——植入 6.Proxy——代理类 7.Aspect——切面 底层逻辑 开发流程 1.导入依…

八、手把手教你搭建SpringCloudAlibaba之Sentinel服务降级之慢调用

SpringCloud Alibaba全集文章目录&#xff1a; 零、手把手教你搭建SpringCloudAlibaba项目 一、手把手教你搭建SpringCloud Alibaba之生产者与消费者 二、手把手教你搭建SpringCloudAlibaba之Nacos服务注册中心 三、手把手教你搭建SpringCloudAlibaba之Nacos服务配置中心 …