zoukankan      html  css  js  c++  java
  • 手写Spring Ioc框架

    一、Spring体系结构

      1、Spring是一个轻量级一站式企业开发解决方案。

    Spring成员 描述
    Spring framework spring的基础,包括ioc、aop及spring mvc、spring template等
    Spring boot 尽量减少框架本身的学习成本以及开发成本,让开发人员更多的关注和开发业务代码;主要特点就是   纯注解、零配置(无Spring配置文件)、自动装配、起步依赖
    Spring Cloud 分布式/微服务一站式开发框架
    Spring data 解决的是数据交互(mysql、redis、elasticsearch、mongodb、orm等)
    Spring security 主要是针对登陆安全、权限认证等
    Spring oauth2 解决单点登录、用户鉴权等问题

      2、Spring framework的体系结构入下图所示。

        对每一个模块的描述如下表格:

    模块 子模块 描述
    核心容器 Spring-Beans、Spring-Core

    1、这两个模块是Spring的核心模块,包含了控制反转了依赖注入;

    2、其中BeanFactory接口是Spring框架中的核心接口,他是工厂模式的具体实现

    3、BeanFactory使用控制反转和依赖注入解耦了配置、依赖性规范与业务代码

    4、BeanFactory容器实例化后并不会自动实例化Bean,而是等到Bean被使用时,BeanFactory才会对Bean进行实例化和依赖关系装配

    Spring-Context

    1、SpringContext模块架构于核心模块之上,他扩展了BeanFactory,为他添加了Bean生命周期控制、框架事件体系以及资源加载透明化等功能

    2、ApplicationContext是该模块的核心接口,他是BeanFactory的超类

    3、ApplicationContext容器实例化后会对所有的单例Bean进行实例化和依赖关系的装配,使其处于可用状态

    Expression Expression是统一表达式语言的扩展模块,可以查询和管理运行中的对象
    AOP和设备支持 Spring-AOP Spring-AOP是Spring的另一个核心模块,是AOP主要的实现模块
    Spring-Aspects Spring-Aspects模块集成自AspectJ,主要是为Spring-AOP提供多种AOP实现方案
    Spring-Instrument Spring-Instrument模块应该是AOP的支援模块,主要作用是在JVM启动时,生成一个代理类,开发人员可以通过代理类在运行时改变类的字节,从而改变一个类的功能,从而实现AOP功能
    数据访问与集成 Spring-JDBC

    1、Spring-JDBC模块是Spring提供的JDBC抽象框架的主要实现模块,用于简化SpringJDBC

    2、Spring-JDBC主要提供模板方式、关系数据库对象化方式、SimpleJdbc方式、事务管理来简化JDBC编程

    3、Spring-JDBC的主要实现类是JdbcTemplate、SimpleJdbcTemplate、NamedParameterJdbcTemplater

    数据访问及集成 Spring-TX Spring-TX是SpringJDBC的事务控制实现模块。
    Spring-ORM Spring-ORM模块是ORM框架支持模块,主要集成Hibernate、JPA等用于资源管理、数据访问的实现和事务策略
    Spring-JMS Spring-JMS能够发送和接口信息,从Spring4开始,还提供了Spring-Messaging模块的支撑
    Spring-OXM5

    Spring-OXM模块主要提供一个抽象层以支撑OXM:将JAVA对象映射成XML数据,或者将XML数据映射成JAVA对象

    Web    Spring-Web Spring-Web为Spring提供了最基础的Web支持,主要建立在核心容器之上,通过Servlet或者Listeners来初始化IOC容器,也包含一些与Web相关的支持
    Spring-WebMVC Spring-WebMVC是一个Web-Servlet模块,实现了SpringMVC的Web应用
    Spring-WebSocket Spring-WebSocket主要是与Web前端的全双工通讯的协议
    Spring-WebFlux  Spring-WebFlux是一个新的非阻塞函数式ReactiveWeb框架,可以用来建立异步的,非阻塞,事件驱动的服务,并且扩展性非常好
     报文发送 Spring-Messaging  Spring-Messaging是从Spring4开始加入的新模块,主要职责是为Spring框架集成一些基础的报文传送应用
     Test Spring-Test Spring-Test主要为测试提供支持。 

    二、手写Spring IOC框架

      手写框架可以由简入繁,一步步深入。

      以   apis--->service--->dao为例,进行数据查询,dao中需要注入datasource,service需要注入dao,apis需要注入service。

      V1为直接手动赋值写法,V2为使用了配置文件加载的写法,V3是借鉴了Spring的类体系后的写法

    1、V1版本(手动注入)

      IOC主要是使用了构造函数或者是setter方法进行了依赖注入,那么V1版本就先模拟依赖注入部分。

      dao:

    @Slf4j
    public class UserDaoImpl implements UserDao {
        private BasicDataSource dataSource;
        public UserDaoImpl(BasicDataSource dataSource){
            this.dataSource = dataSource;
        }
        @Override
        public UserDo findUserById(String id) throws Exception {
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
            UserDo userDo = new UserDo();
            try {
                //加载数据库驱动
                Class.forName(dataSource.getDriverClassName());
                //获取数据库连接
                connection = (Connection) DriverManager.getConnection(dataSource.getUrl(),dataSource.getUsername(),dataSource.getPassword());
                //sql预处理
                String sql = "select * from user where id = ?";
                preparedStatement = (PreparedStatement) connection.prepareStatement(sql);
                //参数设置
                preparedStatement.setString(1,id);
                //执行sql
                resultSet = preparedStatement.executeQuery();
                //循环结果集
                while (resultSet.next()){
                    userDo.setId(resultSet.getInt("id"));
                    userDo.setUsername(resultSet.getString("username"));
                    userDo.setAddress(resultSet.getString("address"));
                    userDo.setSex(resultSet.getString("sex"));
                    userDo.setBirthday(resultSet.getDate("birthday"));
                    log.info("查询到用户信息,id=【{}】,username=【{}】", resultSet.getString("id"), resultSet.getString("username"));
                }
    
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                //释放资源
                if (resultSet != null){
                    try {
                        resultSet.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if (preparedStatement != null){
                    try {
                        preparedStatement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if (connection != null){
                    try {
                        connection.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
            return userDo;
        }
    }

      service:

    public class UserServiceImpl implements UserService {
        private UserDao userDao;
        @Override
        public UserDo findUserById(String id) throws Exception{
            return userDao.findUserById(id);
        }
        public UserServiceImpl(UserDao userDao){
            this.userDao = userDao;
        }
    }

      apis:

    @Slf4j
    public class UserApis {
        private UserService userService;
        public UserApis(UserService userService){
            this.userService = userService;
        }
        public void findUserById(String id) throws Exception{
            UserDo userDo = userService.findUserById(id);
            log.info("=================={}=================", userDo);
        }
    }

      V1版本测试类:

        @Test
        public void writeFrameV1() throws Exception {
            BasicDataSource dataSource = new BasicDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://*********:3306/ins_buying_0");
            dataSource.setUsername("*******");
            dataSource.setPassword("********");
            UserApis userApis = new UserApis(new UserServiceImpl(new UserDaoImpl(dataSource)));
            userApis.findUserById("2");
        }

      可以看到,直接将datasource注入到了UserDao,然后将UserDao注入到了UserService,将Userservice注入到了Userapis,最终完成调用,并在UserDao中使用datasource做了数据库查询操作。

    2、V2版本(加载配置文件)

      在写之前,先梳理一下思路及应该有哪些对象:

        (1)应该有个spring的配置文件,配置文件中有bean标签,标签内有id、name、class、initMethod等属性,同时可能存在属性对应的property标签(有可能多个),那么这里就使用一个BeanDefinition对象来封装每一个Bean的配置信息

        (2)property标签中存在name、ref、value属性,其中value属性表示的是简单类型,ref表示的是引用类型,这里我们创建一个PropertyValue对象,来封装property标签,同时使用TypeStringValue来封装简单类型,使用RuntimeBeanRefeerance来封装引用类型

        (3)对于加载流程,就是加载spring配置文件进行解析,将所有的配置信息放入一个map集合中

        (4)对于执行流程,我们使用一个单例map存储单例的bean,保证单例bean只有一个,因此使用bean时,从单例map中获取,如果获取不到,就创建bean,如果创建成功,且是单例bean,则将bean放入单例map中

        (5)最重要的就是创建bean的步骤了,首先根据beanName从BeanDefinition中获取配置信息,然后使用反射获取类对象,然后循环property集合,对集合中的每一个属性进行赋值操作。

      总体流程如上所示,那么接下来就一步步实现:

        (1)创建配置文件及BeanDefinition对象

    <beans>
    
        <bean id="userService" class="com.lcl.galaxy.spring.frame.service.UserServiceImpl">
            <property name="userDao" ref="userDao"/>
        </bean>
    
        <bean id="userDao" class="com.lcl.galaxy.spring.frame.dao.UserDaoImpl">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://******:3306/ins_buying_0"/>
            <property name="username" value="*******"/>
            <property name="password" value="******"/>
        </bean>
    </beans>
    package com.lcl.galaxy.spring.frame.domain;
    
    import lombok.Data;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Data
    public class MyBeanDefinition {
    
        private String clazzName;
    
        private String scope;
    
        private String beanName;
    
        private String initMethod;
    
        private List<MyPropertyValue> propertyValueList = new ArrayList<>();
    
        private final String SCOPE_SINGLETON = "singleton";
        private final String SCOPE_PROTOTYPE = "prototype";
    
        public MyBeanDefinition(String clazzName, String beanName) {
            this.clazzName = clazzName;
            this.beanName = beanName;
        }
    
        public boolean isSingleton(){
            if(SCOPE_SINGLETON.equals(scope)){
                return true;
            }
            return false;
        }
    
        public boolean isPrototype(){
            if(SCOPE_PROTOTYPE.equals(scope)){
                return true;
            }
            return false;
        }
    
        public void addPropertyValue(MyPropertyValue pv) {
            propertyValueList.add(pv);
        }
    }

        (2)property标签中存在name、ref、value属性,其中value属性表示的是简单类型,ref表示的是引用类型,这里我们创建一个PropertyValue对象,来封装property标签,同时使用TypeStringValue来封装简单类型,使用RuntimeBeanRefeerance来封装引用类型

    package com.lcl.galaxy.spring.frame.domain;
    
    import lombok.Data;
    
    @Data
    public class MyPropertyValue {
    
        private String name;
    
        private Object typedStringValue;
    
        public MyPropertyValue(String name, Object typedStringValue) {
            this.name = name;
            this.typedStringValue = typedStringValue;
        }
    }
    package com.lcl.galaxy.spring.frame.domain;
    
    import lombok.Data;
    
    @Data
    public class MyTypedStringValue {
    
        private String value;
    
        private Class<?>  targetType;
    
        public MyTypedStringValue(String value) {
            this.value = value;
        }
    }
    package com.lcl.galaxy.spring.frame.domain;
    
    import lombok.Data;
    
    @Data
    public class MyRuntimeBeanReference {
    
        private String ref;
    
        public MyRuntimeBeanReference(String ref) {
            this.ref = ref;
        }
    }

        (3)对于加载流程,就是加载spring配置文件进行解析,将所有的配置信息放入一个map集合中

        /**
         * 加载配置文件
         */
        public void init() {
            String location = "write-frame-beans.xml";
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(location);
            Document document = createDocument(inputStream);
            registerBeanDefinition(document.getRootElement());
        }
    
        /**
         * 输入流传唤为Document
         * @param inputStream
         * @return
         */
        private Document createDocument(InputStream inputStream) {
            Document document = null;
            SAXReader saxReader = new SAXReader();
            try {
                document = saxReader.read(inputStream);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return document;
        }
    
        /**
         * 记载配置文件
         * @param rootElement
         */
        private void registerBeanDefinition(Element rootElement) {
            List<Element> elements = rootElement.elements();
            for (Element element : elements) {
                String name = element.getName();
                if ("bean".equals(name)) {
                    parseDefaultElement(element);
                } else {
                    parseCustomElement(element);
                }
            }
        }
    
        /**
         * 解析自定义标签
         * @param element
         */
        private void parseCustomElement(Element element) {
        }
    
        /**
         * 解析bean标签,封装为Bedefinition,并将BeanDefinition放入map中
         * @param beanElement
         */
        private void parseDefaultElement(Element beanElement) {
            if (beanElement == null) {
                return;
            }
    
            String id = beanElement.attributeValue("id");
            String name = beanElement.attributeValue("name");
            String clazzName = beanElement.attributeValue("class");
            if (clazzName == null || "".equals(clazzName)) {
                return;
            }
    
            String initMethod = beanElement.attributeValue("initMethod");
            String scope = beanElement.attributeValue("scope");
            scope = scope != null ? scope : "singleton";
            String beanName = id == null ? name : id;
            Class<?> clazzType = null;
            try {
                clazzType = Class.forName(clazzName);
                beanName = beanName == null ? clazzType.getName() : beanName;
                MyBeanDefinition beanDefinition = new MyBeanDefinition(clazzName, beanName);
                beanDefinition.setInitMethod(initMethod);
                beanDefinition.setScope(scope);
                List<Element> propertyElements = beanElement.elements();
                for (Element propertyElement : propertyElements) {
                    parsePropertyElement(beanDefinition, propertyElement);
                }
                beanDefinitions.put(beanName, beanDefinition);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        对property集合赋值

        /**
         * 为BeanDefinition的property集合赋值
         * @param beanDefinition
         * @param propertyElement
         */
        private void parsePropertyElement(MyBeanDefinition beanDefinition, Element propertyElement) {
            String name = propertyElement.attributeValue("name");
            String value = propertyElement.attributeValue("value");
            String ref = propertyElement.attributeValue("ref");
    
            if(value != null && !"".equals(value) && ref != null && !"".equals(ref)){
                return;
            }
    
            MyPropertyValue pv = null;
            if(value != null && !"".equals(value)){
                MyTypedStringValue typedStringValue = new MyTypedStringValue(value);
                Class<?> targetType = getTypeFieldName(beanDefinition.getClazzName(), name);
                typedStringValue.setTargetType(targetType);
                pv = new MyPropertyValue(name, typedStringValue);
                beanDefinition.addPropertyValue(pv);
            }else{
                MyRuntimeBeanReference runtimeBeanReference = new MyRuntimeBeanReference(ref);
                pv = new MyPropertyValue(name, runtimeBeanReference);
                beanDefinition.addPropertyValue(pv);
            }
        }
    
        /**
         * 获取简单类型
         * @param clazzName
         * @param name
         * @return
         */
        private Class<?> getTypeFieldName(String clazzName, String name) {
            try {
                Class<?> clazz = Class.forName(clazzName);
                Field field = clazz.getDeclaredField(name);
                return field.getType();
            } catch (Exception e) {
                log.info("================== clazzName,name ====================,{}==========,{}",clazzName, name);
                e.printStackTrace();
            }
            return null;
        }

        (4)对于执行流程,我们使用一个单例map存储单例的bean,保证单例bean只有一个,因此使用bean时,从单例map中获取,如果获取不到,就创建bean,如果创建成功,且是单例bean,则将bean放入单例map中

        public void findUserById(String id) throws Exception {
            UserService userService = (UserService) getBean("userService");
            UserDo userDo = userService.findUserById(id);
            log.info("=================={}=================", userDo);
        }
    
        /**
         * 根据bean名称获取bean对象
         * @param beanName
         * @return
         */
        private Object getBean(String beanName) {
            Object object = singletonObjects.get(beanName);
            if (object != null) {
                return object;
            }
    
            MyBeanDefinition beanDefinition = beanDefinitions.get(beanName);
            if (beanDefinition == null || beanDefinition.getClazzName() == null) {
                return null;
            }
    
            if (beanDefinition.isSingleton()) {
                object = createBean(beanDefinition);
                this.singletonObjects.put(beanName, object);
            } else if (beanDefinition.isPrototype()) {
                object = createBean(beanDefinition);
            }
            return object;
        }

        (5)最重要的就是创建bean的步骤了,首先根据beanName从BeanDefinition中获取配置信息,然后使用反射获取类对象,然后循环property集合,对集合中的每一个属性进行赋值操作。

        /**
         * 创建bean
         * @param beanDefinition
         * @return
         */
        private Object createBean(MyBeanDefinition beanDefinition) {
            
            String clazzName = beanDefinition.getClazzName();
            try {
                Class<?> clazz = Class.forName(clazzName);
                if(clazz == null){
                    return null;
                }
                Constructor<?> constructor = clazz.getConstructor();
                Object object = constructor.newInstance();
                populateBean(object, beanDefinition);
                initMethod();
               return object;
                
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
        /**
         * 处理初始化方法
         */
        private void initMethod() {
        }
    
        /**
         * 为对象赋值
         * @param object
         * @param beanDefinition
         */
        private void populateBean(Object object, MyBeanDefinition beanDefinition) {
            List<MyPropertyValue> propertyValueList = beanDefinition.getPropertyValueList();
            for (MyPropertyValue propertyValue: propertyValueList) {
                String name = propertyValue.getName();
                Object value = propertyValue.getTypedStringValue();
                Object valueToUse = null;
                if(value instanceof MyTypedStringValue){
                    MyTypedStringValue myTypedStringValue = (MyTypedStringValue) value;
                    String stringValue = myTypedStringValue.getValue();
                    Class<?> targetType = myTypedStringValue.getTargetType();
                    if(targetType == Integer.class){
                        valueToUse = Integer.parseInt(stringValue);
                    }else if(targetType == String.class){
                        valueToUse = String.valueOf(stringValue);
                    }else{
    
                    }
                }else if(value instanceof MyRuntimeBeanReference){
                    MyRuntimeBeanReference myRuntimeBeanReference = (MyRuntimeBeanReference) value;
                    valueToUse = getBean(myRuntimeBeanReference.getRef());
                }
                Class<?> clazz = object.getClass();
                try {
                    Field declaredField = clazz.getDeclaredField(name);
                    declaredField.setAccessible(true);
                    declaredField.set(object, valueToUse);
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
            }
        }

      可以看到,对于简单类型的属性,直接进行了赋值操作,对于引用类型,则使用了递归调用创建Bean对象,然后进行赋值操作

    3、V3版本(仿照Spring源码类体系结构)

      由于V3版本是借鉴SpringIOC源码编写,那先来看一下Spring IOC中的一些核心概念及类的继承体系。

      基础概念及对比

      Spring容器:Spring容器就是IOC容器,底层是一个BeanFactory(使用简单工厂实现),spring容器分为基础容器(BeanFactory)和高级容器(ApplicationContext)

        BeanFactory和ApplicationContext的区别:(1)ApplicationContext是继承自BeanFactory接口;(2)BeanFactory创建Bean实例是在第一次获取该Bean的实例时创建;(3)ApplicationContext创建Bean实例是在初始化的时候,一次性创建所有的单例bean实例。

        BeanPostProcessor和BeanFactoryPostProcessor的区别:(1)BeanFactoryPostProcessor是在创建Bean对象前,对Bean的封装信息Beandefinition对象做处理;例如context:property标签,可以加载指定路径的properties文件,同时将文件中的key-value放入容器;也可将BeanDefinition中的${}占位符进行替换(2)BeanPostProcessor是在对象实例化后,对Bean对象做后置处理。例如:AOP

      BeanFactory和FactoryBean的区别:(1)BeanFactory是Spring的基础容器,管理着spring中需要管理的所有Bean。(2)FactoryBean只是spring容器管理的bean的一员,只不过该bean对象比较特殊,可以产生一些指定类型的bean。  

      继承体系 

       如上图所示,是BeanFactory的类体系结构(这里没有包含AppllicationContext体系)可以将其描述为四级接口继承体系。

      针对以上接口的大致内容描述如下:

    接口级别 描述 BeanFactory接口 作用
    一级接口 Beanfactory作为主接口,不继承任何接口,可以称为一级接口 BeanFactory 是Spring Bean的根接口,提供获取bean、是否包含bean、是否单例、是否原型、获取bean类型获取bean等功能接口
    二级接口 AutowireCapableBeanFactory、HierarchicalBeanFactory、ListableBeanFactory三个子接口继承了BeanFactory,可以称为二级接口 AutowireCapableBeanFactory 提供工厂的装配功能
    ListableBeanFactory 提供容器内bean实例的枚举功能,这边不会考虑父容器内的实例
    HierarchicalBeanFactory 提供父容器的访问功能
    三级接口 ConfigurableBeanFactory继承了二级接口HierarchicalBeanFactory,同时和继承了SingletonBeanRegistry接口 ConfigurableBeanFactory 提供factory的配置功能
    四级接口 ConfigurableListableBeanFactory是一个更强大的接口,继承了以上所有的接口。 ConfigurableListAbleBeanFactory 集大成者,提供解析bean、修改bean定义、初始化单例等功能

      根据上述内容,可以暂定一下手写Ioc框架的类划分

        1、加载主入口&调用主入口

        2、BeanFactory体系:用于加载Bendefinition信息和创建Bean对象

        3、reader:用于读取xml文件或Document文件

        4、registory:用于注册BeanDefinition信息和单例Bean信息

        5、utils:用于处理Dodument对象或通过反射操作一些内容

        6、resource:加载配置文件

        7、aware:实现了aware接口的类,就可以获取BeanFactory对象

      其中utils和resource属于工具类范畴,在最后会附上代码。

      其实逻辑代码跟V2是一样的,主要是对接口、类、方法进行了封装,最主要的就是BeanFactory体系,仿照Spring源码中的BeanFactory体系,我也创建了一些体系,在说BeanFactory之前,先说一下registory的接口和类:

        registory

      我在代码中提供了两个registory接口MyBeanDefinitonRegistory和MySingletonRegistory,分别用来注册BeanDefinition和单例Bean对象

      其中MyBeanDefinitionRegistory接口提供了BeanDefinition注册、根据beanName获取BeanDefinition对象两个方法

    public interface MyBeanDefinitionRegisty {
    
        void registry(String beanName, MyBeanDefinition beanDefinition);
    
        MyBeanDefinition getBeanDefinition(String beanName);
    }

      MySingletonRegistory提供了根据beanName获取Bean实例对象和添加Bean实例对象两个方法

    package com.lcl.galaxy.spring.frame.V3.register;
    
    public interface MySingletonRegistry {
        Object getSingletonBean(String beanName);
    
        void addSingleton(String beanName, Object object);
    }

      为MySingletonRegistor提供了一个默认实现类MyDefaultSingletonBeanFactory,用来向单例Bean的map集合中添加单例Bean或获取单例Bean

    public class MyDefaultSingletonBeanRegistory implements MySingletonRegistry {
    
        private Map<String, Object> singletonObjects = new HashMap<>();
    
        @Override
        public Object getSingletonBean(String beanName) {
            return singletonObjects.get(beanName);
        }
    
        @Override
        public void addSingleton(String beanName, Object object) {
            singletonObjects.put(beanName, object);
        }
    }

      BeanFactory

      说完registry,然后重点说一下BeanFactory类,仿照Spring源码中的BeanFactory体系创建的BeanFactory体系如下:

       首先,创建了一个根接口MyBeanFactory,该接口只提供根据BeanName获取Bean对象

    public interface MyBeanFactory {
        Object getBean(String beanName);
    }

      创建了两个二级接口MyAutowireCapableBeanFactory和MyListableBeanFactory,其中MyAutowireCapableBeanFactory提供了创建bean对象的方法,而MyListableBeanFactory则提供了根据指定类型获取所有bean名称集合方法和根据类型所有Bean对象集合方法

    public interface MyAutowireCapableBeanFactory extends MyBeanFactory {
        Object createBean(String beanName, MyBeanDefinition myBeanDefinition);
    }
    public interface MyListableBeanFactory extends MyBeanFactory {
        List<String> getBeanNamesByType(Class<?> type);
        <T> List<T> getBeansByType(Class<?> type);
    }

      然后创建接口的实现类,首先创建一个顶层的抽象类MyAbstructBeanFactory,其实现MyListableBeanFactory接口,同时集成上述的MyDefualtSingletonRegistory类,在该类中去实现getBean方法。

      在该类的getBean方法中,主要做了四步:单例bean是否已存在、获取bean对应的BeanDefinition对象、根据BeanDefinition创建Bean实例、将Bean实例放入单例Bean的map中

      由于该类继承了MyDefualtSingletonRegistory,因此也拥有了单例Bean的注册和获取方法,因此对于上面说的四步中,第一步和第四步直接可以调用父类的方法完成操作。

      那么在该方法中,还有第二步获取Bendefiniton对象和创建Bean实例两个步骤,具体如何创建,交由子类处理,此处只使用抽象的方法做了封装。(从这里可以看到,具体每个类做哪些事情,还是划分的比较清楚的)

    public abstract class MyAbstractBeanFactory extends MyDefaultSingletonBeanRegistory implements MyListableBeanFactory {
    
        @Override
        public Object getBean(String beanName) {
    
            Object bean = getSingletonBean(beanName);
            if(bean != null){
                return bean;
            }
            MyBeanDefinition beanDefinition = getBeanDefinition(beanName);
            if(beanDefinition == null){
                return null;
            }
    
            if(beanDefinition.isSingleton()){
                bean = createBean(beanName, beanDefinition);
                addSingleton(beanName, beanDefinition);
            }else if(beanDefinition.isPrototype()){
                bean = createBean(beanName, beanDefinition);
            }
            return bean;
        }
    
        public abstract Object createBean(String beanName, MyBeanDefinition beanDefinition);
    
        public abstract MyBeanDefinition getBeanDefinition(String beanName);
    
    }

      然后创建负责创建对象的BeanFactory:MyAbstructAutowireCapableBeanFactory,该类实现MyAutowireCapableBeanFactory接口,同时集成上一步的MyAbstructBeanFactory类,由于MyAbstructBeanFactory中有抽象的创建bean实例的方法,而MyAutowireCapableBeanFactory接口中也存在该方法,因此在MyAbstructAutowireCapableBeanFactory中实现该方法,具体实现内容其实和V2版本一致,具体就不再描述了,直接上代码:

    public abstract class MyAbstructAutowireCapableBeanFactory extends MyAbstractBeanFactory implements MyAutowireCapableBeanFactory {
        @Override
        public Object createBean(String beanName, MyBeanDefinition beanDefinition) {
            Class<?> clazz = getResolvedClass(beanDefinition);
            Object object = createInstance(clazz);
            populateBean(object, beanDefinition);
            initalBean(object, beanDefinition);
            return object;
        }
    
        /**
         * bean的初始化
         * @param object
         * @param beanDefinition
         */
        private void initalBean(Object object, MyBeanDefinition beanDefinition) {
            //aware接口处理
            if(object instanceof MyAware){
                if(object instanceof MyBeanFactoryAware){
                    ((MyBeanFactoryAware)object).setBeanFactory(this);
                }
            }
            //对实现了IniallizingBean接口的类,调用他的afterProperties方法
            //如果Bean中init-method属性有值,则调用指定的方法
            initMethod(object, beanDefinition);
        }
    
        private void initMethod(Object object, MyBeanDefinition beanDefinition) {
            String method = beanDefinition.getInitMethod();
            if(method != null && !"".equals(method)){
                ReflectUtils.invokeMethod(object, method);
            }
        }
    
        private Object createInstance(Class<?> clazz){
            //如果有实例工厂,则通过实例工厂创建Bean实例
            //如果有工厂方法,则通过工厂方法创建Bean实例
            //如果都没有,则使用构造函数创建Bean实例
            return ReflectUtils.createObject(clazz);
        }
    
        private Class<?> getResolvedClass(MyBeanDefinition beanDefinition){
            String clazzName = beanDefinition.getClazzName();
            try {
                Class<?> clazz = Class.forName(clazzName);
                return clazz;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 为对象赋值
         * @param object
         * @param beanDefinition
         */
        private void populateBean(Object object, MyBeanDefinition beanDefinition) {
            List<MyPropertyValue> propertyValueList = beanDefinition.getPropertyValueList();
            for (MyPropertyValue propertyValue: propertyValueList) {
                String name = propertyValue.getName();
                Object value = propertyValue.getTypedStringValue();
                Object valueToUse = null;
                if(value instanceof MyTypedStringValue){
                    MyTypedStringValue myTypedStringValue = (MyTypedStringValue) value;
                    String stringValue = myTypedStringValue.getValue();
                    Class<?> targetType = myTypedStringValue.getTargetType();
                    if(targetType == Integer.class){
                        valueToUse = Integer.parseInt(stringValue);
                    }else if(targetType == String.class){
                        valueToUse = String.valueOf(stringValue);
                    }else{
    
                    }
                }else if(value instanceof MyRuntimeBeanReference){
                    MyRuntimeBeanReference myRuntimeBeanReference = (MyRuntimeBeanReference) value;
                    valueToUse = getBean(myRuntimeBeanReference.getRef());
                }
                ReflectUtils.setProperty(object, name, valueToUse);
            }
        }
    
    }

      最后一个创建的就是功能的集大成者:MyDefaultListableBeanFactory,其实现MyBeanDefinitionRegistory接口,同时集成上一个类MyAbstructAutowireCapableBeanFactory,由于继承了MyBeanDefinitionRegistory接口,因此就需要实现对应的Beandefinition的注册和获取方法。

    public class MyDefaultListableBeanFactory extends MyAbstructAutowireCapableBeanFactory implements MyBeanDefinitionRegisty {
    
    
        private Map<String, MyBeanDefinition> beanDefinitions = new HashedMap();
    
        @Override
        public void registry(String beanName, MyBeanDefinition beanDefinition) {
            beanDefinitions.put(beanName, beanDefinition);
        }
    
        @Override
        public MyBeanDefinition getBeanDefinition(String beanName) {
            return beanDefinitions.get(beanName);
        }
    
        @Override
        public List<String> getBeanNamesByType(Class<?> type) {
            return null;
        }
    
        @Override
        public <T> List<T> getBeansByType(Class<?> clazz) {
            List<T> list = new ArrayList<>(beanDefinitions.size());
            for(MyBeanDefinition beanDefinition : beanDefinitions.values()){
                String clazzName = beanDefinition.getClazzName();
                Class<?> type = resolveClassName(clazzName);
                if(clazz.isAssignableFrom(type)){
                    Object bean = getBean(beanDefinition.getBeanName());
                    list.add((T) bean);
                }
            }
            return list;
        }
    
        private Class<?> resolveClassName(String clazzName) {
            try {
                return Class.forName(clazzName);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

      整体码完。。。。。。。

    附录、工具类代码附录

      接下来,附上对应的工具类内容

      1、主入口:

    @Slf4j
    @Data
    public class SpringIocFrame {
    
        public MyDefaultListableBeanFactory init(){
            String location = "write-frame-beans.xml";
    
            //加载配置文件
            MyResources resources = new MyClassPathResource(location);
    
            //创建BeanFactory
            MyDefaultListableBeanFactory beanFactory = new MyDefaultListableBeanFactory();
    
            //
            MyXmlBeanDefinitionReader reader = new MyXmlBeanDefinitionReader(beanFactory);
    
            reader.loadBeanDefinitions(resources);
    
            return beanFactory;
        }
    
        public void findUserById(String id, MyDefaultListableBeanFactory beanFactory) throws Exception {
            UserService userService = (UserService) beanFactory.getBean("userService");
            UserDo userDo = userService.findUserById(id);
            log.info("=================={}=================", userDo);
        }
    
    
    }

      2、reader:

    package com.lcl.galaxy.spring.frame.V3.reader;
    
    import com.lcl.galaxy.spring.frame.V2.domain.MyBeanDefinition;
    import com.lcl.galaxy.spring.frame.V2.domain.MyPropertyValue;
    import com.lcl.galaxy.spring.frame.V2.domain.MyRuntimeBeanReference;
    import com.lcl.galaxy.spring.frame.V2.domain.MyTypedStringValue;
    import com.lcl.galaxy.spring.frame.V3.register.MyBeanDefinitionRegisty;
    import lombok.extern.slf4j.Slf4j;
    import org.dom4j.Element;
    
    import java.lang.reflect.Field;
    import java.util.List;
    
    @Slf4j
    public class MyXmlBeanDefinitionDocumentReader {
        
        private MyBeanDefinitionRegisty registy;
        
        public MyXmlBeanDefinitionDocumentReader(MyBeanDefinitionRegisty registy) {
            super();
            this.registy = registy;
        }
    
        /**
         * 按照spring标签语义进行解析
         * @param rootElement
         */
        public void loadBeanDefinitions(Element rootElement) {
            List<Element> elements = rootElement.elements();
            for (Element element : elements) {
                String name = element.getName();
                if ("bean".equals(name)) {
                    parseDefaultElement(element);
                } else {
                    parseCustomElement(element);
                }
            }
        }
    
    
        /**
         * 解析自定义标签
         * @param element
         */
        private void parseCustomElement(Element element) {
        }
    
        /**
         * 解析bean标签,封装为Bedefinition,并将BeanDefinition放入map中
         * @param beanElement
         */
        private void parseDefaultElement(Element beanElement) {
            if (beanElement == null) {
                return;
            }
    
            String id = beanElement.attributeValue("id");
            String name = beanElement.attributeValue("name");
            String clazzName = beanElement.attributeValue("class");
            if (clazzName == null || "".equals(clazzName)) {
                return;
            }
    
            String initMethod = beanElement.attributeValue("initMethod");
            String scope = beanElement.attributeValue("scope");
            scope = scope != null ? scope : "singleton";
            String beanName = id == null ? name : id;
            Class<?> clazzType = null;
            try {
                clazzType = Class.forName(clazzName);
                beanName = beanName == null ? clazzType.getName() : beanName;
                MyBeanDefinition beanDefinition = new MyBeanDefinition(clazzName, beanName);
                beanDefinition.setInitMethod(initMethod);
                beanDefinition.setScope(scope);
                List<Element> propertyElements = beanElement.elements();
                for (Element propertyElement : propertyElements) {
                    parsePropertyElement(beanDefinition, propertyElement);
                }
                this.registy.registry(beanName, beanDefinition);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 为BeanDefinition的property集合赋值
         * @param beanDefinition
         * @param propertyElement
         */
        private void parsePropertyElement(MyBeanDefinition beanDefinition, Element propertyElement) {
            String name = propertyElement.attributeValue("name");
            String value = propertyElement.attributeValue("value");
            String ref = propertyElement.attributeValue("ref");
    
            if(value != null && !"".equals(value) && ref != null && !"".equals(ref)){
                return;
            }
    
            MyPropertyValue pv = null;
            if(value != null && !"".equals(value)){
                MyTypedStringValue typedStringValue = new MyTypedStringValue(value);
                Class<?> targetType = getTypeFieldName(beanDefinition.getClazzName(), name);
                typedStringValue.setTargetType(targetType);
                pv = new MyPropertyValue(name, typedStringValue);
                beanDefinition.addPropertyValue(pv);
            }else{
                MyRuntimeBeanReference runtimeBeanReference = new MyRuntimeBeanReference(ref);
                pv = new MyPropertyValue(name, runtimeBeanReference);
                beanDefinition.addPropertyValue(pv);
            }
        }
    
        /**
         * 获取简单类型
         * @param clazzName
         * @param name
         * @return
         */
        private Class<?> getTypeFieldName(String clazzName, String name) {
            try {
                Class<?> clazz = Class.forName(clazzName);
                Field field = clazz.getDeclaredField(name);
                return field.getType();
            } catch (Exception e) {
                log.info("================== clazzName,name ====================,{}==========,{}",clazzName, name);
                e.printStackTrace();
            }
            return null;
        }
    }
    package com.lcl.galaxy.spring.frame.V3.reader;
    
    import com.lcl.galaxy.spring.frame.V3.register.MyBeanDefinitionRegisty;
    import com.lcl.galaxy.spring.frame.V3.resource.MyResources;
    import com.lcl.galaxy.spring.frame.V3.utils.DocumentUtils;
    import org.dom4j.Document;
    
    import java.io.InputStream;
    
    public class MyXmlBeanDefinitionReader {
    
        private MyBeanDefinitionRegisty registy;
    
        public MyXmlBeanDefinitionReader(MyBeanDefinitionRegisty registy) {
            this.registy = registy;
        }
    
        public void loadBeanDefinitions(MyResources resources) {
            InputStream inputStream = resources.getResourceAsStream();
            Document document = DocumentUtils.readInputStream(inputStream);
            MyXmlBeanDefinitionDocumentReader xmlBeanDefinitionDocumentReader = new MyXmlBeanDefinitionDocumentReader(registy);
            xmlBeanDefinitionDocumentReader.loadBeanDefinitions(document.getRootElement());
        }
    }

      3、resource

    public class MyClassPathResource implements MyResources {
    
        private String location;
    
        public MyClassPathResource(String location){
            this.location = location;
        }
    
        @Override
        public InputStream getResourceAsStream() {
            return MyResources.class.getClassLoader().getResourceAsStream(location);
        }
    }
    public interface MyResources {
        InputStream getResourceAsStream();
    }

      4、utils

    public class DocumentUtils {
        public static Document readInputStream(InputStream inputStream) {
            SAXReader saxReader = new SAXReader();
            try {
                Document document = saxReader.read(inputStream);
                return document;
            } catch (DocumentException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    public class ReflectUtils {
    
        /**
         * 通过反射获取对象
         * @param args
         * @return
         */
        public static Object createObject(Class<?> clazz, Object... args){
            try {
                Constructor<?> constructor = clazz.getConstructor();
                return constructor.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 通过反射设置属性值
         * @param object
         * @param name
         * @param valueToUse
         */
        public static void setProperty(Object object, String name, Object valueToUse){
            Class<?> clazz = object.getClass();
            try {
                Field field = clazz.getDeclaredField(name);
                field.setAccessible(true);
                field.set(object, valueToUse);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 通过反射获取字段的类型
         * @param beanClassName
         * @param name
         * @return
         */
        public static Class<?> getTypeByFieldName(String beanClassName, String name){
            try {
                Class<?> clazz = Class.forName(beanClassName);
                Field field = clazz.getDeclaredField(name);
                return field.getType();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 通过反射执行init方法
         * @param object
         * @param initMethod
         */
        public static void invokeMethod(Object object, String initMethod){
            Class<?> clazz = object.getClass();
            try {
                Method declaredMethod = clazz.getDeclaredMethod(initMethod);
                declaredMethod.setAccessible(true);
                declaredMethod.invoke(object);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    三、总结

      对于IoC框架的手写,其实V2版本已经实现了功能,V3版本只是借鉴Spring源码对V2版本进行了梳理,代码逻辑没有变化,只是对类的集成体系、设计模式等做了相应的调整,其实手写完V3版本,就已经大致了解Spring源码中相关类的继承体系,对于啃Spring Ioc的源码有很大的帮助,

  • 相关阅读:
    2017ICPC南宁补题
    H. The Game of Life
    I
    Twice Equation
    (贪心+队列)String
    Marcin and Training Camp
    莫比乌斯函数模版
    HDU-1695 莫比乌斯反演
    Steps to One DP+莫比乌斯反演
    Educational Codeforces Round 62 (Rated for Div. 2)
  • 原文地址:https://www.cnblogs.com/liconglong/p/14164087.html
Copyright © 2011-2022 走看看