Spring源碼,Spring源碼中getBean的簡單流程

 2023-11-19 阅读 33 评论 0

摘要:在學習Sring的時候,免不了經常見如下的代碼 VirtuousApplicationContext applicationContext = new VirtuousApplicationContext(AppConfig.class);UserInterFace userInterFace = (UserInterFace) applicationContext.getBean("userService"); 這就是

在學習Sring的時候,免不了經常見如下的代碼

 VirtuousApplicationContext applicationContext = new VirtuousApplicationContext(AppConfig.class);UserInterFace userInterFace = (UserInterFace) applicationContext.getBean("userService");

這就是Spring給我們造的輪子,于是這次就深入了解了下Spring的bean的加載流程,對BeanDefinition、BeanPostProcessor進行更好的了解。模擬寫一下Spring獲取Bean的流程
1.如上代碼,我們的一個接口交給Spring管理的時候,Spring通過getBean幫我們拿到我們交給他們的對象。
我們仿照Srping 也新建一個ApplicationContext類,在這個類里面有個對象,也就是入參傳入的Config的類,于是寫一個config的構造函數。

  public VirtuousApplicationContext(Class configClass) {this.configClass = configClass;}

最開始的第一行代碼,我們知道它的功能就是對Spring進行掃描,是否是有交給Spring管理的單列Bean對象,沒有就進行創建。 那么接下來的思路就是在這個構造函數中進行對項目代碼的掃描操作。通過ComponentScan進行Spring的掃描

 if(configClass.isAnnotationPresent(ComponentScan.class)){ComponentScan  componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);String path = componentScanAnnotation.value();System.out.println("掃描路徑:"+path);path = path.replace(".","/");ClassLoader classLoader = VirtuousApplicationContext.class.getClassLoader();URL resource = classLoader.getResource(path);File file = new File(resource.getFile());// 找到文件if(file.isDirectory()){for(File f: file.listFiles()){String absolutePath = f.getAbsolutePath();absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));absolutePath = absolutePath.replace("\\", ".");try {Class<?> clazz = classLoader.loadClass(absolutePath);// 表示一個類是一個Beanif (clazz.isAnnotationPresent(Component.class)) {if (BeanPostProcessor.class.isAssignableFrom(clazz)) {BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();beanPostProcessorList.add(instance);}// bean的名字Component componentAnnotation = clazz.getAnnotation(Component.class);String beanName = componentAnnotation.value();if ("".equals(beanName)) {beanName = Introspector.decapitalize(clazz.getSimpleName());}BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setType(clazz);if (clazz.isAnnotationPresent(Scope.class)) {Scope scopeAnnotation = clazz.getAnnotation(Scope.class);String value = scopeAnnotation.value();beanDefinition.setScope(value);} else {// 單列beanDefinition.setScope("singleton");}beanDefinitionMap.put(beanName, beanDefinition);}} catch (ClassNotFoundException | NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}}

在掃描過程中,我們的思路是將單列Bean放入一個Map中。第二行代碼中,通過getBean獲取到我們需要的對象,我們就仿照通過beanName拿到我們交給Spring管理而需要用到的對象。

  if(!beanDefinitionMap.containsKey(beanName)){throw  new RuntimeException();}BeanDefinition beanDefinition =  beanDefinitionMap.get(beanName);if(beanDefinition.getScope().equals("singleton")){// 單列Object singletonBean = singletonObjects.get(beanName);if(singletonBean == null){singletonBean = createBean(beanName,beanDefinition);singletonObjects.put(beanName,singletonBean);}return  singletonBean;} else {// 原型Object  prototypeBean = createBean(beanName,beanDefinition);return  prototypeBean;}

Spring源碼、在這個過程中,如果我們獲取到的單列的getBean就返回,如果沒有的話,就通過創建Bean,創建成功后也是通過放入Map中。由此引入創建createBean的過程

 Class clazz = beanDefinition.getType();Object instance = null;try {instance = clazz.getConstructor().newInstance();for (Field field : clazz.getDeclaredFields()) {if (field.isAnnotationPresent(Autowired.class)) {field.setAccessible(true);// 獲取beanfield.set(instance, getBean(field.getName()));}}if (instance instanceof BeanNameAware) {((BeanNameAware)instance).setBeanName(beanName);}// BeanPostProcessorfor (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);}if (instance instanceof InitializingBean) {((InitializingBean)instance).afterPropertiesSet();}for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);}} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();}return  instance;

以上就是一個簡單粗糙的Spring獲取getBean的簡單原理。當然,Spring源碼底層的實現肯定不是這么簡單的代碼實現。做下記錄,以便繼續深入的學習。

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://808629.com/181986.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 86后生记录生活 Inc. 保留所有权利。

底部版权信息