title: 暑假最后几天!肝爆(手写)一个Spring之Day3上午
date: 2022-08-15 23:26:59
categories:
- 手写spring
Day03上午—Spring IoC顶层结构设计
core(顶层接口)核心模块
-
区分BeanFactory和FactoryBean:
- BeanFactory:Bean工厂,是个工厂,也就是IoC容器的最高层接口,作用时管理Bean
- FactoryBean:工厂Bean,是一个Bean,作用时产生其他Bean的实例
-
创建core包,再撸
package com.czh.spring.framework.core; public interface MyFactoryBean { }
package com.czh.spring.framework.core; /** * 单例工厂的顶层设计 */ public interface MyBeanFactory { /** * 根据beanName从IoC容器中获取一个实例Bean * @param beanName * @return * @throws Exception */ Object getBean(String beanName) throws Exception; public Object getBean(Class<?> beanClass) throws Exception; }
beans(配置封装)模块
-
创建包beans.config,再撸
-
BeanDefinition:主要用于保存Bean相关的配置信息
package com.czh.spring.framework.beans.config; import lombok.Data; @Data public class MyBeanDefinition { //原生Bean的全类名 private String beanClassName; //标记是否延时加载,默认为false private boolean lazyInit = false; //保存beanName,在IoC容器中存储的key private String factoryBeanName; }
-
BeanWrapper:主要用于封装创建后的实例对象,代理对象或者原生对象都有BeanWrapper来保存
package com.czh.spring.framework.beans; public class MyBeanWrapper { private Object wrappedInstance; public MyBeanWrapper(Object wrappedInstance){ this.wrappedInstance = wrappedInstance; } public Object getWrappedInstance(){ return this.wrappedInstance; } // 返回代理以后的Class // 可能会是这个 $Proxy0 public Class<?> getWrappedClass(){ return this.wrappedInstance.getClass(); } }
context(IoC容器)模块
-
AbstractApplicationContext:IoC容器实现类的顶层抽象类,实现IoC容器相关的公共逻辑。为了尽可能地简单化,暂时只设计一个refresh()方法。
package com.czh.spring.framework.context.support; public abstract class MyAbstractApplicationContext { //受保护,只提供给子类重写 public void refresh() throws Exception {} }
-
DefaultListableBeanFactory:众多IoC容器的典型代表,暂时只设计一个顶层的IoC缓存,也就是beanDefinitionMap。
package com.czh.spring.framework.beans.support; import com.czh.spring.framework.beans.config.MyBeanDefinition; import com.czh.spring.framework.context.support.MyAbstractApplicationContext; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class MyDefaultListableBeanFactory extends MyAbstractApplicationContext { //存储注册信息的BeanDefinition,伪IOC容器 protected final Map<String, MyBeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, MyBeanDefinition>(); }
-
BeanDefinitionReader:完成对application.properties配置文件的解析工作,实现看代码(请细品)
package com.czh.spring.framework.beans.support; import com.czh.spring.framework.beans.config.MyBeanDefinition; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Properties; /** * 对配置文件进行查找、读取、解析 */ public class MyBeanDefinitionReader { private List<String> registerBeanClasses = new ArrayList<String>(); private Properties config = new Properties(); //固定配置文件中的key,相对于XML的规范 private final String SCAN_PACKAGE = "scanPackage"; public MyBeanDefinitionReader(String...locations){ //通过URL定位找到其所对应的文件,然后转换为文件流 InputStream is = this.getClass().getClassLoader().getResourceAsStream(locations[0].replace("classpath:","")); try { config.load(is); } catch (IOException e) { e.printStackTrace(); }finally { if(null != is){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } doScanner(config.getProperty(SCAN_PACKAGE)); } 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()){ //如果是目录就接着递归扫描 doScanner(scanPackage+"."+file.getName()); }else { if(!file.getName().endsWith(".class"))continue;//如果不是class文件就跳过 String className = (scanPackage + "." +file.getName().replace(".class",""));//拼接出className registerBeanClasses.add(className); } } } public Properties getConfig(){ return this.config; } //把配置文件中扫描到的所有配置信息转换为BeanDefinition对象,便于后面IoC操作 public List<MyBeanDefinition> loadBeanDefinitions(){ ArrayList<MyBeanDefinition> beanDefinitionList = new ArrayList<>(); try { for (String className : registerBeanClasses) { Class<?> beanClass = Class.forName(className); if(beanClass.isInterface())continue;//如果是接口就跳过,因为接口从类中获取 beanDefinitionList.add(doCreateBeanDefinition(toLowerFirstCase(beanClass.getSimpleName()),beanClass.getName())); Class<?>[] interfaces = beanClass.getInterfaces(); for (Class<?> anInterface : interfaces) { beanDefinitionList.add(doCreateBeanDefinition(anInterface.getName(),beanClass.getName())); } } } catch (ClassNotFoundException e) { e.printStackTrace(); } return beanDefinitionList; } //把每一个配置信息解析成一个BeanDefinition private MyBeanDefinition doCreateBeanDefinition(String factoryBeanName, String beanClassName) { MyBeanDefinition beanDefinition = new MyBeanDefinition(); beanDefinition.setBeanClassName(beanClassName); beanDefinition.setFactoryBeanName(factoryBeanName); return beanDefinition; } //将类名首字母改为小写 private String toLowerFirstCase(String simpleName){ char[] chars = simpleName.toCharArray(); chars[0] += 32; return String.valueOf(chars); } }
-
ApplicationContext:直接接触用户的入口,实现DefaultListableBeanFactory中的refresh()方法和BeanFactory的getBean()方法,完成IoC、DI、AOP的衔接
package com.czh.spring.framework.context; import com.czh.spring.framework.beans.config.MyBeanDefinition; import com.czh.spring.framework.beans.support.MyBeanDefinitionReader; import com.czh.spring.framework.beans.support.MyDefaultListableBeanFactory; import com.czh.spring.framework.core.MyBeanFactory; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; public class MyApplicationContext extends MyDefaultListableBeanFactory implements MyBeanFactory { private String[] configLocations; private MyBeanDefinitionReader reader; public MyApplicationContext(String...configLocations){ this.configLocations = configLocations; try { refresh(); } catch (Exception e) { e.printStackTrace(); } } @Override public void refresh() throws Exception { //1.定位配置文件 reader = new MyBeanDefinitionReader(this.configLocations); //2.加载配置文件,扫描相关的类,封装成BeanDefinition List<MyBeanDefinition> beanDefinitionList = reader.loadBeanDefinitions(); //3.注册,把配置信息放到容器中(伪IoC容器) doRegisterBeanDefinition(beanDefinitionList); //4.把不是延时加载的类提前初始化 doAutowired(); } //只处理非延时加载的情况 private void doAutowired() { for (Map.Entry<String, MyBeanDefinition> beanDefinitionEntry : beanDefinitionMap.entrySet()) { String beanName = beanDefinitionEntry.getKey(); if(!beanDefinitionEntry.getValue().isLazyInit()){ try { getBean(beanName); } catch (Exception e) { e.printStackTrace(); } } } } private void doRegisterBeanDefinition(List<MyBeanDefinition> beanDefinitionList) throws Exception { for (MyBeanDefinition beanDefinition : beanDefinitionList) { if(super.beanDefinitionMap.containsKey(beanDefinition.getFactoryBeanName())){ throw new Exception("The \""+beanDefinition.getFactoryBeanName()+"\" is exist!!!"); } super.beanDefinitionMap.put(beanDefinition.getFactoryBeanName(),beanDefinition); //到这容器初始化完毕 } } // TODO 依赖注入从这里开始,读取BeanDefinition中的信息,然后通过反射创建一个实例并返回,不会放原始对象进去,spring // TODO 里面会用一个BeanWrapper进行一次包装 @Override public Object getBean(String beanName) throws Exception { return null; } @Override public Object getBean(Class<?> beanClass) throws Exception { return getBean(beanClass.getName()); } public String[] getBeanDefinitionNames(){ return this.beanDefinitionMap.keySet().toArray(new String[getBeanDefinitionCount()]); } public int getBeanDefinitionCount(){ return this.beanDefinitionMap.size(); } public Properties getConfig(){ return this.reader.getConfig(); } }
-
ApplicationContextAware:通过实现侦听机制得到一个回调方法,从而得到一个上下文,即ApplicationContext,先做设计,后面再看情况
package com.czh.spring.framework.context; /** * 通过解耦方式获得IOC容器的顶层设计 * 后面将通过一个监听器去扫描所有的类,只要实现了此接口, * 将自动调用setApplicationContext()方法,从而将IOC容器注入到目标类中 * Created by czh */ public interface MyApplicationContextAware { void setApplicationContext(MyApplicationContext applicationContext); }