暑假最后几天!肝爆(手写)一个Spring之Day3上午


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);
    }
    

今日战况概览

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luelueking

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值