开发者社区 > 博文 > bean的一生
分享
  • 打开微信扫码分享

  • 点击前往QQ分享

  • 点击前往微博分享

  • 点击复制链接

bean的一生

  • hz****
  • 2024-01-17
  • IP归属:北京
  • 6920浏览

    你曾读spring源码 “不知所云”、“绞尽脑汁”、“不知所措”嘛🤣🤣🤣

    那这篇文章可能会对你有所帮助,小编尝试用简单、易懂的例子来模拟spring经典代码👉Spring Bean生命周期及扩展点,

    让你能够轻松的读懂Spring Bean的生命周期,更加深入的理解Spring。


    那好,下面小编将从如下几个步骤来介绍✍️✍️✍️

    1》回顾Spring Bean相关知识点

       1.1什么是Bean

       1.2什么是 Spring Bean 的生命周期

       1.3 Spring Bean 的生命周期的扩展点

    2模拟 Spring Bean 生命周期及扩展点

       2.1 流程图

       2.2 代码功能介绍

       2.3 代码实现

       2.3.1 指定扫描路径

       2.3.2 扫描、生成classList

       2.3.3 bean定义、建立beanName映射关系、保存beanPostProcessor对象

       2.3.4 实例化bean、对象填充属性、执行award方法、BeanPostProcessor干预、初始化、放入单例池、获取bean

       2.3.5 业务类实现

       2.3.6 运行结果

    3总结


    1 》回顾Spring Bean相关知识点

    1. 1 什么是Bean

    对于普通的 Java 对象,当 new 的时候创建对象,然后该对象就能够使用了。一旦该对象不再被使用,则由 Java 自动进行垃圾回收。

    而 Spring 中的对象是 bean,bean 和普通的 Java 对象没啥大的区别,只不过 Spring 不再自己去 new 对象了,而是由 IoC 容器去帮助我们实例化对象并且管理它,我们需要哪个对象,去问 IoC 容器要即可。IoC 其实就是解决对象之间的耦合问题,Spring Bean 的生命周期完全由容器控制。

    简而言之,bean 是由 Spring IoC 容器实例化、组装和管理的对象。

    1.2 什么是 Spring Bean 的生命周期

    • 普通的Java对象生命周期:

    实例化

    该对象不再被使用时通过垃圾回收机制进行回收

    • Spring Bean 的生命周期:

    实例化 Instantiation

    属性赋值 Populate

    初始化 Initialization

    销毁 Destruction

    1.3 Spring Bean 的生命周期的扩展点

    • Bean 自身的方法

    实例化 -> 属性赋值 -> 初始化 -> 销毁

    • 容器级的方法(BeanPostProcessor 一系列接口)

    主要是后处理器方法,比如InstantiationAwareBeanPostProcessor、BeanPostProcessor 接口方法。

    这些接口的实现类是独立于 Bean 的,并且会注册到 Spring 容器中。

    在 Spring 容器创建任何 Bean 的时候,这些后处理器都会发生作用。

    • Bean 级生命周期方法

    可以理解为 Bean 类直接实现接口的方法,比如 BeanNameAware、BeanFactoryAware、ApplicationContextAware、InitializingBean、DisposableBean 等方法,这些方法只对当前 Bean 生效。



    如上为Spring Bean知识的回顾👏👏👏,如果忘记了,没关系,让咱们在代码中寻找记忆。下面咱们开始模拟Spring Bean 生命周期。

    2 》 模拟 Spring Bean 生命周期及扩展点

    在看代码之前,首先,先给大家展示一下流程图、代码功能介绍,方便大家理解。

    2.1 》 流程图

    2.2 》 代码功能介绍

    Application.java 启动类,实例化spring容器

    AnnotationConfig.java 配置类,指定扫描路径

    AnnotationApplicationContext.java 核心类,bean创建、获取

    BeanDefinition.java BeanDefinition定义

    SqBeanPostProcessor.java 后置处理器,初始化前后对bean进行干预

    User.java 业务类,用户对象,用户信息设置

    UserService.java 业务类,用户service,实现BeanNameAware、InitializingBean

    spring注解模拟

       Autowired.java

       Component.java

       Lazy.java

       Scope.java

       ComponentScan.java

    spring接口模拟

       BeanNameAware.java

       BeanPostProcessor.java

       InitializingBean.java


    现在咱们开始看代码、看代码、看代码✌️✌️✌️

    2.3》 代码实现

    2.3.1》 AnnotationConfig.java 指定扫描路径

    @ComponentScan("com.hz.spring.demo.service")
    public class AnnotationConfig { 
     
    }

    2.3.2 》 AnnotationApplicationContext.java 扫描、生成classList

    • 根据配置类config,获取扫描路径
    • 通过类加载器获取target class 路径
    • 扫描文件路径,加载类文件,放入classList中,为类操作做准备
    public AnnotationApplicationContext(Class<AnnotationConfig> config) {  
      this.config = config;   
       try {        
       // 扫描        
       ComponentScan componentScan = config.getAnnotation(ComponentScan.class);       
        // com.hz.spring.demo.service        
        String path = componentScan.value();        
        path = path.replace(".", "/");        
        // 通过类加载器 获取target class 路径        
        ClassLoader classLoader = AnnotationApplicationContext.class.getClassLoader();        
        URL url = classLoader.getResource(path);        
        if (url != null) {            
            // 获取classList            
            File file = new File(url.getFile());           
            List<Class<?>> classList = this.scanAndGetClassList(classLoader, file);            
            // bean定义、建立beanName映射关系、保存beanPostProcessor对象           
             this.compBdMap(classList);            
            // 实例化。创建bean。放入单例池            
            // 核心、核心、核心            
             this.instanceBean();        
             }   
         } catch (Exception e) {        
             log.error("AnnotationApplicationContext error:", e);   
         }
    }

    扫描、加载class

    private List<Class<?>> scanAndGetClassList(ClassLoader classLoader, File file) {    
    List<Class<?>> classList = Lists.newArrayList();    
    if (file.isDirectory()) {       
         File[] files = file.listFiles();        
         if (files != null) {            
             for (File f : files) {                
                 try {                    
                     String absolutePath = f.getAbsolutePath();                    
                     // Window target文件路径                    
                     // D:\company\comp\company-rest\target\test-classes\com\hz\spring2\service\User.class                    
                     // D:\company\comp\company-rest\target\test-classes\com\hz\spring2\service\UserService.class                    
                     // absolutePath = absolutePath.substring(absolutePath.indexOf("com\\"), absolutePath.indexOf(".class"));                    
                     // absolutePath = absolutePath.replace("\\", ".");                    
                     // Mac target文件路径                    
                     // /Users/huzhong5/hz/IdeaProjects/yb-claim/psc-invoicing/target/test-classes/com/hz/spring/demo/service/UserService.class                    
                     absolutePath = absolutePath.substring(absolutePath.indexOf("com/"), absolutePath.indexOf(".class"));                    
                     absolutePath = absolutePath.replace("/", ".");                   
                     // absolutePath: com.hz.spring.demo.service.UserService                    
                     Class<?> clazz = classLoader.loadClass(absolutePath);                    
                     classList.add(clazz);                
                   } catch (Exception e) {                    
                       log.error("scanAndGetClassList error e:", e);               
                    }           
              }        
         }    
     }    
         return classList;
     }

    2.3.3 》 bean定义、建立beanName映射关系、保存beanPostProcessor对象

    • 遍历classList
    • 创建BeanDefinition、BeanDefinition赋值属性、建立beanName与BeanDefinition映射关系
    • 保存beanPostProcessor对象
    private void compBdMap(List<Class<?>> classList) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
     {    
     for (Class<?> clazz : classList) {        
     // 遍历 @Component("") 类。设置bean属性        
     if (clazz.isAnnotationPresent(Component.class)) {            
     Component clazzAnnotation = clazz.getAnnotation(Component.class);           
      String beanName = clazzAnnotation.value();           
       BeanDefinition beanDefinition = new BeanDefinition();           
        beanDefinition.setBeanClass(clazz);           
         if (clazz.isAnnotationPresent(Scope.class)) {                
            Scope scopeAnnotation = clazz.getAnnotation(Scope.class);               
            String scope = scopeAnnotation.value();                
            beanDefinition.setScope(scope);           
         } else {                
           // 默认单例               
            beanDefinition.setScope(SCOPE_SINGLETON);           
          }           
           // userService:beanDefinition            
           beanDefinitionMap.put(beanName, beanDefinition);            
           // 保存beanPostProcessor对象            
           // 通过反射获取对象            
           // clazz : SQYCBeanPostProcessor            
           if (BeanPostProcessor.class.isAssignableFrom(clazz)) {                
              BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();               
              beanPostProcessorList.add(instance);           
           }       
        }    
       }
     }

    遍历beanDefinitionMap,判断beanDefinition作用域

    • 作用域为单例Bean,放入单例池
    • 作用域为多例Bean,多次创建
    private void instanceBean() {   
        Set<Map.Entry<String, BeanDefinition>> entries = beanDefinitionMap.entrySet();   
        for (Map.Entry<String, BeanDefinition> entry : entries) {       
            BeanDefinition beanDefinition1 = entry.getValue();        
            String beanName = entry.getKey();        
            if (SCOPE_SINGLETON.equals(beanDefinition1.getScope())) {            
               if (!singletonObjects.containsKey(beanName)) {                
                // create                
                Object instance = this.doCreateBean(beanName, beanDefinition1);                
                singletonObjects.put(beanName, instance);            
                }        
            } else {            
               this.doCreateBean(beanName, beanDefinition1);       
            }    
        }
     }

    2.3.4 》 实例化bean、对象填充属性、执行award 方法、BeanPostProcessor干预、初始化、放入单例池、获取bean

    • 实例化bean
    • 对象填充属性
    • BeanNameAware 设置beanName
    • BeanPostProcessor,初始化前后进行bean干预
    • InitializingBean 初始化,设置属性
    • bean创建完成,返回bean,放入单例池
    private Object doCreateBean(String beanName, BeanDefinition beanDefinition1) {    
        // com.hz.spring.demo.service.UserService    
        Class<?> beanClass = beanDefinition1.getBeanClass();    
        try {        
        // 实例化bean        
        Object instance = beanClass.getConstructor().newInstance();        
        // 填充属性。为bean添加属性。如:userService 添加属性 user        
        // 解析Autowired注解的属性        
        Field[] declaredFields = beanClass.getDeclaredFields();        
        for (Field declaredField : declaredFields) {            
            if (declaredField.isAnnotationPresent(Autowired.class)) {               
            // user 他也是一个bean。执行从单例池获取就可以                
            // 根据beanName获取对象                
            Object bean = this.getBean(declaredField.getName());                
            declaredField.setAccessible(true);               
            // 将属性declaredField 赋值给 instance               
            declaredField.set(instance, bean);            
            }        
        }        
        // award.通过beanNameAward实现获取beanName        
        if (instance instanceof BeanNameAware) {            
            ((BeanNameAware) instance).setBeanName(beanName);        
        }       
        // 初始化之前。BeanPostProcessor干预。应用场景:AOP 、属性注入、资源回收        
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {            
            instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);        
        }        
        // 初始化。在属性注入完成后调用。可以对属性进行一些改动       
        if (instance instanceof InitializingBean) {            
            try {                
                ((InitializingBean) instance).afterPropertiesSet();            
            } catch (Exception e) {                
                log.error("doCreateBean InitializingBean error:", e);            
            }        
        }        
        
        // 初始化之后。BeanPostProcessor干预      
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {            
            instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);        
        }       
        return instance;    
    } catch (Exception e) {        
       log.error("doCreateBean error:", e);    
    }    
    return null;
    }
    • 根据beanName获取bean
    public Object getBean(String beanName) {    
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);    
        String scope = beanDefinition.getScope();    
        if (SCOPE_SINGLETON.equals(scope)) {        
            Object bean = singletonObjects.get(beanName);        
            if (bean == null) {            
                bean = this.doCreateBean(beanName, beanDefinition);        
            }        
            return bean;    
        } else if (SCOPE_PROTOTYPE.equals(scope)) {        
            return this.doCreateBean(beanName, beanDefinition);    
        }    
        return null;
    }

    BeanPostProcessor实现类定义

    @Component("sqBeanPostProcessor")
    @Slf4j
    public class SqBeanPostProcessor implements BeanPostProcessor {    
        @Override    
        public Object postProcessBeforeInitialization(Object bean, String beanName) {        
            log.info("SqBeanPostProcessor {} 初始化之前", beanName);        
            return bean;   
        }    
        
        @Override    
        public Object postProcessAfterInitialization(Object bean, String beanName) {        
            log.info("SqBeanPostProcessor {} 初始化之后", beanName);        
            // 可以改变对象。很强大    
            return bean;   
        }
    }

    如上,bean创建流程就完成啦✌️✌️✌️

    2.3.5 》 业务类实现

    下面,咱们看看业务类怎样对Spring Bean 进行扩展,

    UserService业务核心类定义,实现BeanNameAware、InitializingBean,对bean进行干预;

    • test() 方法,获取用户属性、beanName
    • setBeanName() 通过beanNameAward实现获取beanName
    • afterPropertiesSet() 在属性注入完成后调用,可以对属性进行一些改动
    @Component("userService")
    @Scope(value = "singleton")
    @Slf4j
    public class UserService implements BeanNameAware, InitializingBean {   
         @Autowired    
         private User user;    
         /**     
         * 可以通过spring award回调方法实现     
         * beanName应用场景:     
         * spring + dubbo。dubbo暴露服务,单个服务的地址可能是beanName的名称组成     
         */   
          private String beanName;    
          /**     
          * 所有属性填充后。获得     
          */    
          private String userName;    
          
          public void test() {        
              log.info("UserService test() user.age:{},beanName:{},userName:{}", user.getAge(), beanName, userName);    
          }    
          
          /**  
          * BeanNameAward    
          *     
          * @param beanName     
          */   
          @Override    
          public void setBeanName(String beanName) {        
              this.beanName = beanName;        
              log.info("UserService setBeanName() beanName:{}", beanName);    
          }   
           
          /**    
           * InitializingBean     
           * 所有属性填充后获得     
           *     
           * @throws Exception     
           */    
           @Override    
           public void afterPropertiesSet() throws Exception {        
               this.userName = "w";        
               this.user.setAge("24");        
               log.info("UserService afterPropertiesSet() userName:{},age:{}", userName, user.getAge());    
           }
    }

    2.3.6 》 运行结果

    Application.java 启动类,实例化spring容器,获取userService对象,调用test方法。

    @Slf4j 
    public class Application { 
        public static void main(String[] args) { 
            AnnotationApplicationContext configWebApplicationContext = new AnnotationApplicationContext(AnnotationConfig.class); 
            UserService userService = (UserService) configWebApplicationContext.getBean("userService"); 
            userService.test(); 
        } 
    }

    下面我们来运行下,结果如下:

    17:41:39.466 [main] INFO com.hz.spring.demo.service.SqBeanPostProcessor - SqBeanPostProcessor sqBeanPostProcessor 初始化之前
    17:41:39.471 [main] INFO com.hz.spring.demo.service.SqBeanPostProcessor - SqBeanPostProcessor sqBeanPostProcessor 初始化之后
    17:41:39.471 [main] INFO com.hz.spring.demo.service.SqBeanPostProcessor - SqBeanPostProcessor user 初始化之前
    17:41:39.472 [main] INFO com.hz.spring.demo.service.SqBeanPostProcessor - SqBeanPostProcessor user 初始化之后
    17:41:39.474 [main] INFO com.hz.spring.demo.service.UserService - UserService setBeanName() beanName:userService
    17:41:39.474 [main] INFO com.hz.spring.demo.service.SqBeanPostProcessor - SqBeanPostProcessor userService 初始化之前
    17:41:39.474 [main] INFO com.hz.spring.demo.service.UserService - UserService afterPropertiesSet() userName:w,age:24
    17:41:39.474 [main] INFO com.hz.spring.demo.service.SqBeanPostProcessor - SqBeanPostProcessor userService 初始化之后
    17:41:39.474 [main] INFO com.hz.spring.demo.service.UserService - UserService test() user.age:24,beanName:userService,userName:w


    3 》 总结

    如上为Spring Bean生命周期及扩展点代码模拟, 希望对大家有所帮助。🤝🤝🤝

    文章数
    1
    阅读量
    173

    作者其他文章