IOC容器构造之注册BeanDefinition源码分析

解析完配置文件,接下来便是BeanDefinition的注册了。为了不至于每次用到配置信息的时候都去解析一遍配置文件,我们需要将解析结果保存起来。而保存解析结果这个过程就是BeanDefinition的注册。既然是保存,那就需要一个保存的容器,这个容器就是HashMap。于是BeanDefinition的注册就变成了将解析之后的BeanDefinition信息保存在HashMap中这样一个操作。具体实现过程,请看源码分析。
BeanDefinition注册开始
注册从BeanDefinitionReaderUtils类的registerBeanDefinition方法开始。
beanName和别名的注册
从代码中可以看出,BeanDefinition的注册分成了两部分,通过beanName的注册和通过别名的注册。先来分析通过beanName注册BeanDefinition的方式。
registry的类型
registry此时的类型是DefaultListableBeanFactory,那进入DefaultListableBeanFactory的 registerBeanDefinition方法。
这里写图片描述这里写图片描述
这个方法中先判断是不是有相同名字的BeanDefinition已经注册过了,如果有,但是不允许覆盖,那么只能让程序抛出异常。如果没有相同的名字注册过,那就执行正常的注册过程,以beanName为key,BeanDefinition为value保存在beanDefinitionMap中。
接下来再看通过别名注册BeanDefinition的方式。
这里写图片描述
通过别名注册的方式也比较简单,如果beanName和别名相同的话,就从aliasMap中删掉别名。为什么要删掉呢?因为别名和beanName相同,在获取BeanDefinition的时候,不管是根据beanName来获取还是根据别名来获取,key都是一样,所以这样的别名没别要保存起来。如果beanName和别名不相同的话,就把别名当做key,beanName当做value保存在aliasMap中,到此BeanDefinition注册完成。当然,在分析源码的过程中可能有些地方没有分析到。前面也有提到,我们分析是主线,也就是主要的过程,至于非常细节的部分,感兴趣的朋友也可以自己研究下,毕竟Spring源码是如此的博大精深。
总结:BeanDefinition的注册过程实质就是将BeanDefinition保存在以beanName为key,BeanDefinition为value的Map中的过程。到此IOC容器已经构建好,但这时的IOC容器还只是光有一个壳,没有内容。我们知道IOC容器的作用是管理对象之间的引用关系,也就是对象之间的引用关系还没有填充到IOC容器里面。那么下面要做的事就是去填充IOC容器。
未完待续。。。。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IOC(Inversion of Control)即控制反转,是一种设计思想,它将程序的控制权从代码中转移到了外部容器中,在容器中管理对象的创建、销毁、依赖注入等。 实现IOC容器的思路如下: 1. 扫描指定包路径下的所有类文件,找到所有带有注解的类。 2. 解析注解,生成BeanDefinition对象,保存Bean的相关信息,如类名、类路径、作用域、依赖等。 3. 将所有BeanDefinition对象保存到BeanDefinitionMap中,以便后续使用。 4. 根据BeanDefinitionMap中的信息创建Bean对象,包括实例化、初始化、依赖注入等。 5. 将创建好的Bean对象保存到BeanMap中,以便后续使用。 6. 实现Bean的依赖注入,即根据Bean之间的依赖关系,将需要注入的Bean注入到目标Bean中。 7. 可以提供通过名称、类型、注解等方式获取Bean对象的方法。 下面是一个简单的注解注册bean的示例代码: ``` @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Component { String value() default ""; } public class BeanDefinition { private String className; private Class<?> clazz; private Scope scope; // 省略getter、setter方法 } public class BeanFactory { private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(); private Map<String, Object> beanMap = new HashMap<>(); public void scan(String... packages) { for (String packageName : packages) { scanPackage(packageName); } } private void scanPackage(String packageName) { String packagePath = packageName.replace(".", "/"); URL url = getClass().getClassLoader().getResource(packagePath); if (url == null) { return; } File packageDir = new File(url.getFile()); if (!packageDir.isDirectory()) { return; } for (File file : packageDir.listFiles()) { String fileName = file.getName(); if (file.isDirectory()) { scanPackage(packageName + "." + fileName); } else if (fileName.endsWith(".class")) { String className = packageName + "." + fileName.substring(0, fileName.length() - 6); try { Class<?> clazz = Class.forName(className); Component component = clazz.getAnnotation(Component.class); if (component != null) { BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setClassName(className); beanDefinition.setClazz(clazz); beanDefinition.setScope(Scope.SINGLETON); // 默认为单例 String beanName = component.value(); if (StringUtils.isBlank(beanName)) { beanName = StringUtils.uncapitalize(clazz.getSimpleName()); } beanDefinitionMap.put(beanName, beanDefinition); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } } } public void register(String beanName, Class<?> clazz) { BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setClassName(clazz.getName()); beanDefinition.setClazz(clazz); beanDefinition.setScope(Scope.SINGLETON); beanDefinitionMap.put(beanName, beanDefinition); } public <T> T getBean(String beanName) { BeanDefinition beanDefinition = beanDefinitionMap.get(beanName); if (beanDefinition == null) { return null; } Object bean = beanMap.get(beanName); if (bean == null) { bean = createBean(beanDefinition); beanMap.put(beanName, bean); } return (T) bean; } private Object createBean(BeanDefinition beanDefinition) { Class<?> clazz = beanDefinition.getClazz(); Object bean = null; try { bean = clazz.newInstance(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { Autowired autowired = field.getAnnotation(Autowired.class); if (autowired != null) { Object value = getBean(field.getName()); field.setAccessible(true); field.set(bean, value); } } } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } return bean; } } @Component("userService") public class UserService { @Autowired private UserDao userDao; public void sayHello() { userDao.sayHello(); } } @Component("userDao") public class UserDao { public void sayHello() { System.out.println("Hello, UserDao!"); } } public class App { public static void main(String[] args) { BeanFactory beanFactory = new BeanFactory(); beanFactory.scan("com.example"); UserService userService = beanFactory.getBean("userService"); userService.sayHello(); } } ``` 以上代码中,@Component是自定义的注解,用于标记需要注册Bean的类。在BeanFactory中,scan方法会扫描指定的包路径下所有带有@Component注解的类,并将其注册Bean。 register方法可以手动注册一个Bean,getBean方法用于获取一个Bean对象。createBean方法用于创建Bean对象,并对其所有被@Autowired注解标记的字段进行依赖注入。 在UserService中,@Autowired注解用于标记需要自动注入的UserDao对象。在调用sayHello方法时,会调用UserDao的sayHello方法打印一句话。 运行以上代码,控制台输出: ``` Hello, UserDao! ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值