扫描配置文件
doScanner()是递归方法,当它发现当前扫描的文件是目录时要发生递归,直到找到一个class文件,然后把它的全类名添加到集合中
/** * 扫描资源文件的递归方法 */ private void doScanner(String scanPackage) { URL url = this.getClass().getClassLoader().getResource(scanPackage.replaceAll("\\.", "/")); File classPath = new File(url.getFile()); for (File file : classPath.listFiles()) { if (file.isDirectory()) { //如果是目录则递归调用,直到找到class doScanner(scanPackage + "." + file.getName()); } else { if (!file.getName().endsWith(".class")) { continue; } String className = (scanPackage + "." + file.getName().replace(".class", "")); //className保存到集合 registyBeanClasses.add(className); } } } 复制代码
封装成BeanDefinition
refresh()中接着填充下一步,将上一步扫描好的class集合封装进BeanDefinition
private void refresh() throws Exception { //1、定位,定位配置文件 reader = new BeanDefinitionReader(this.configLocation); //2、加载配置文件,扫描相关的类,把它们封装成BeanDefinition List<BeanDefinition> beanDefinitions = reader.loadBeanDefinitions(); //3、注册,把配置信息放到容器里面 //到这里为止,容器初始化完毕 //4、把不是延时加载的类,提前初始化 } 复制代码
回到BeanDefinitionReader中填充loadBeanDefinitions()方法。逻辑是:扫描class集合,如果是被@Component注解的class则需要封装成BeanDefinition,表示着它将来可以被IOC进行管理。
/** * 把配置文件中扫描到的所有的配置信息转换为BeanDefinition对象 */ public List<BeanDefinition> loadBeanDefinitions() { List<BeanDefinition> result = new ArrayList<>(); try { for (String className : registyBeanClasses) { Class<?> beanClass = Class.forName(className); //如果是一个接口,是不能实例化的,不需要封装 if (beanClass.isInterface()) { continue; } Annotation[] annotations = beanClass.getAnnotations(); if (annotations.length == 0) { continue; } for (Annotation annotation : annotations) { Class<? extends Annotation> annotationType = annotation.annotationType(); //只考虑被@Component注解的class if (annotationType.isAnnotationPresent(Component.class)) { //beanName有三种情况: //1、默认是类名首字母小写 //2、自定义名字(这里暂不考虑) //3、接口注入 result.add(doCreateBeanDefinition(toLowerFirstCase(beanClass.getSimpleName()), beanClass.getName())); Class<?>[] interfaces = beanClass.getInterfaces(); for (Class<?> i : interfaces) { //接口和实现类之间的关系也需要封装 result.add(doCreateBeanDefinition(i.getName(), beanClass.getName())); } break; } } } } catch (Exception e) { e.printStackTrace(); } return result; } /** * 相关属性封装到BeanDefinition */ private BeanDefinition doCreateBeanDefinition(String factoryBeanName, String beanClassName) { BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setFactoryBeanName(factoryBeanName); beanDefinition.setBeanClassName(beanClassName); return beanDefinition; } /** * 将单词首字母变为小写 */ private String toLowerFirstCase(String simpleName) { char [] chars = simpleName.toCharArray(); chars[0] += 32; return String.valueOf(chars); } 复制代码
注册到容器
将BeanDefinition保存为以factoryBeanName为Key的Map
//保存factoryBean和BeanDefinition的对应关系 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(); private void refresh() throws Exception { //1、定位,定位配置文件 reader = new BeanDefinitionReader(this.configLocation); //2、加载配置文件,扫描相关的类,把它们封装成BeanDefinition List<BeanDefinition> beanDefinitions = reader.loadBeanDefinitions(); //3、注册,把配置信息放到容器里面 //到这里为止,容器初始化完毕 doRegisterBeanDefinition(beanDefinitions); //4、把不是延时加载的类,提前初始化 } private void doRegisterBeanDefinition(List<BeanDefinition> beanDefinitions) throws Exception { for (BeanDefinition beanDefinition : beanDefinitions) { if (beanDefinitionMap.containsKey(beanDefinition.getFactoryBeanName())) { throw new Exception("The \"" + beanDefinition.getFactoryBeanName() + "\" is exists!!"); } beanDefinitionMap.put(beanDefinition.getFactoryBeanName(), beanDefinition); } } 复制代码
非懒加载的提前初始化
这是fresh()的最后一步,逻辑是遍历BeanDefinition集合,将非懒加载的Bean提前初始化。
public void refresh() throws Exception { //1、定位,定位配置文件 reader = new BeanDefinitionReader(this.configLocation); //2、加载配置文件,扫描相关的类,把它们封装成BeanDefinition List<BeanDefinition> beanDefinitions = reader.loadBeanDefinitions(); //3、注册,把配置信息放到容器里面(伪IOC容器) //到这里为止,容器初始化完毕 doRegisterBeanDefinition(beanDefinitions); //4、把不是延时加载的类,提前初始化 doAutowired(); } private void doAutowired() { for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : beanDefinitionMap.entrySet()) { String beanName = beanDefinitionEntry.getKey(); if (!beanDefinitionEntry.getValue().isLazyInit()) { try { getBean(beanName); } catch (Exception e) { e.printStackTrace(); } } } } 复制代码
可见实例化的核心方法就是getBean(),它是BeanFactory中的接口方法,下面来具体实现它。
初始化核心方法getBean
核心逻辑也不难:
- 如果已经实例化了,则直接获取实例化后的对象返回即可。如果没有实例化则走后面的逻辑
- 拿到该Bean的BeanDefinition 信息,通过反射实例化
- 将实例化后的对象封装到BeanWrapper中
- 将封装好的BeanWrapper保存到IOC容器(实际就是一个Map)中
- 依赖注入实例化的Bean
- 返回最终实例
/**保存了真正实例化的对象*/ private Map<String, BeanWrapper> factoryBeanInstanceCache = new ConcurrentHashMap<>(); @Override public Object getBean(String beanName) throws Exception { //如果是单例,那么在上一次调用getBean获取该bean时已经初始化过了,拿到不为空的实例直接返回即可 Object instance = getSingleton(beanName); if (instance != null) { return instance; } BeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName); //1.调用反射初始化Bean instance = instantiateBean(beanName, beanDefinition); //2.把这个对象封装到BeanWrapper中 BeanWrapper beanWrapper = new BeanWrapper(instance); //3.把BeanWrapper保存到IOC容器中去 //注册一个类名(首字母小写,如helloService) this.factoryBeanInstanceCache.put(beanName, beanWrapper); //注册一个全类名(如com.lqb.HelloService) this.factoryBeanInstanceCache.put(beanDefinition.getBeanClassName(), beanWrapper); //4.注入 populateBean(beanName, new BeanDefinition(), beanWrapper); return this.factoryBeanInstanceCache.get(beanName).getWrappedInstance(); } private Object instantiateBean(String beanName, BeanDefinition beanDefinition) { //1、拿到要实例化的对象的类名 String className = beanDefinition.getBeanClassName(); //2、反射实例化,得到一个对象 Object instance = null; try { Class<?> clazz = Class.forName(className); instance = clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); } return instance; } 复制代码
依赖注入
上一步中Bean只是实例化了,但是Bean中被@Autowired注解的变量还没有注入,如果这个时候去使用就会报空指针异常。下面是注入的逻辑:
- 拿到Bean中的所有成员变量开始遍历
- 过滤掉没有被@Autowired注解标注的变量
- 拿到被注解变量的类名,并从IOC容器中找到该类的实例(上一步已经初始化放在容器了)
- 将变量的实例通过反射赋值到变量中
private void populateBean(String beanName, BeanDefinition beanDefinition, BeanWrapper beanWrapper) { Class<?> clazz = beanWrapper.getWrappedClass(); //获得所有的成员变量 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { //如果没有被Autowired注解的成员变量则直接跳过 if (!field.isAnnotationPresent(Autowired.class)) { continue; } Autowired autowired = field.getAnnotation(Autowired.class); //拿到需要注入的类名 String autowiredBeanName = autowired.value().trim(); if ("".equals(autowiredBeanName)) { autowiredBeanName = field.getType().getName(); } //强制访问该成员变量 field.setAccessible(true); try { if (this.factoryBeanInstanceCache.get(autowiredBeanName) == null) { continue; } //将容器中的实例注入到成员变量中 field.set(beanWrapper.getWrappedInstance(), this.factoryBeanInstanceCache.get(autowiredBeanName).getWrappedInstance()); } catch (IllegalAccessException e) { e.printStackTrace(); } } } 复制代码
改造
- 第一个改造的点,当然是MVC的地方
GetRequestHandler->handle
网络异常,图片无法展示
|
什么意思呢?就是我要在Springmvc里面 拿到处理好的bean,那么我的controller 也是需要代理的,所以在这个地方加载了spring的ioc容器
这样就把srpingmvc 和spring合起来了
结尾
好了,今天我们把spring ioc的大致流程写了些,其实只是一个最简单的例子,有助于大家去理解spring,下次看看是补补我们的xml 还是把aop写写。