• 10、简单手写spring创建bean


    根据源码我们也可以简单的手写一个bean容器的创建,并解决非AOP循环依赖。这里为了方便,不频繁的切换类,这里直接所有写在了一个类里面,只实现了xml的setter注入。

    1、pom.xml

        <dependencies>
            
            <dependency>
                <groupId>jaxengroupId>
                <artifactId>jaxenartifactId>
                <version>1.2.0version>
            dependency>
            <dependency>
                <groupId>org.dom4jgroupId>
                <artifactId>dom4jartifactId>
                <version>2.1.3version>
            dependency>
            
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <version>1.18.24version>
            dependency>
            
            <dependency>
                <groupId>junitgroupId>
                <artifactId>junitartifactId>
                <version>4.11version>
                <scope>testscope>
            dependency>
            
            <dependency>
                <groupId>org.apache.logging.log4jgroupId>
                <artifactId>log4j-coreartifactId>
                <version>2.19.0version>
            dependency>
            <dependency>
                <groupId>org.apache.logging.log4jgroupId>
                <artifactId>log4j-slf4j2-implartifactId>
                <version>2.19.0version>
            dependency>
    
        dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    2、编写获取bean的方法

    ApplicationContext 接口

    package org.myspringframework.core;
    
    /**
     * MySpring框架应用上下文接口
     **/
    public interface ApplicationContext {
        /**
         * 根据bean的名称获取对应的bean对象
         * @param beanName myspring配置文件中bean标签的id
         * @return 对应的bean对象
         */
        Object getBean(String beanName);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    ClasspathXmlApplicationContext类。这里我们把所有的方法封装在这个类里面(比如 populateBean)。

    package org.myspringframework.core;
    
    import lombok.extern.log4j.Log4j2;
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.Node;
    import org.dom4j.io.SAXReader;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.io.InputStream;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    public class ClasspathXmlApplicationContext implements ApplicationContext {
        private Logger log = LoggerFactory.getLogger("ClasspathXmlApplicationContext");
        private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
        private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
        /**
         * 我们假设Object是工厂
         */
        private final Map<String, Object> singletonFactories = new HashMap<>(16);
    
        private final Map<String, Element> beanLabel = new HashMap<>(16);
    
        /**
         * 解析myspring的配置文件,初始化所有的bean对象
         *
         * @param configLocation spring配置文件的路径,
         *                       注意ClasspathXmlApplicationContext,配置文件应当放到类路径下
         */
        public ClasspathXmlApplicationContext(String configLocation) {
            parse(configLocation);
        }
    
        /**
         * 解析xml
         *
         * @param configLocation
         */
        private void parse(String configLocation) {
            try {
                //解析myspring.xml文件,然后实例化Bean,将Bean存放到singletonObjects集合当中
                //这是dom4j解析XML文件的核心对象
                SAXReader saxReader = new SAXReader();
                //获取一个输入流,指向配置文件
                InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);
                //读文件
                Document document = saxReader.read(in);
                //获取所有的bean标签(从任意位置的节点上选择名称为 bean 的节点。)
                List<Node> beans = document.selectNodes("//bean");
                //先将所有bean标签放入map中
                beans.forEach((node) -> {
                    //System.out.println(node);//rg.dom4j.tree.DefaultElement@1786dec2....
                    //为了使用更加丰富的方法
                    Element beanElm = (Element) node;
                    String beanName = beanElm.attributeValue("id");
                    beanLabel.put(beanName, beanElm);
                });
    
                //遍历map创建对象
                beanLabel.forEach((beanName, beanElm) -> {
                    doGetBean(beanName);
                });
            } catch (DocumentException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 开始获取bean
         *
         * @param beanName
         * @return
         */
        private Object doGetBean(String beanName) {
            Element beanElm = beanLabel.get(beanName);
            String className = beanElm.attributeValue("class");
            log.info("beanName={}", beanName);
            log.info("beanClassName={}", className);
            //先从缓存中获取bean
            Object initInstance = getSingleton(beanName);
            if (null == initInstance) {
                doCreateBean(beanName);
                //创建好了在获取
                initInstance = getSingleton(beanName);
            }
            return initInstance;
        }
    
        /**
         * 创建bean对象
         *
         * @param beanName
         */
        private void doCreateBean(String beanName) {
            Element beanElm = beanLabel.get(beanName);
            String className = beanElm.attributeValue("class");
            //通过反射机制创建对象,将其放到Map集合,提前曝光
            //获取class
            try {
                Class<?> aClass = null;
                aClass = Class.forName(className);
                //获取无参数构造方法
                Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
                //调用无参数构造方法实例bean
                Object bean = declaredConstructor.newInstance();
                //记录日志
                log.info("开始创建bean+" + beanName);
                //放入到三级缓存
                addSingletonFactory(beanName, bean);
                //注入属性
                populateBean(bean, beanElm);
                //在加入到一级缓存
                addSingleton(beanName, bean);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 放入到一级缓存
         *
         * @param beanName
         * @param bean
         */
        private void addSingleton(String beanName, Object bean) {
            singletonObjects.put(beanName, bean);
            earlySingletonObjects.remove(beanName);
            singletonFactories.remove(beanName);
        }
    
        /**
         * 注入属性
         */
        private void populateBean(Object bean, Element beanElm) {
            List<Element> properties = beanElm.elements("property");
            properties.forEach(property -> {
                try {
                    Class<?> aClass = bean.getClass();
                    //获取属性名
                    String propertyName = property.attributeValue("name");
                    //获取属性类型
                    Field field = aClass.getDeclaredField(propertyName);
                    log.info("propertyName: " + propertyName);
                    //获取set方法名称
                    String setMethodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);
                    //获取set方法
                    Method setMethod = aClass.getDeclaredMethod(setMethodName, field.getType());
                    //获取具体的值
                    String value = property.attributeValue("value");
                    String ref = property.attributeValue("ref");
                    if (null != value) {
                        //说明这个值是简单类型
                        //调用set方法(set方法没有返回值)
                        //我们myspring框架声明以下,我们只支持这些8中类型及包装类为简单类型
                        //获取属性类型
                        String propertySimpleType = field.getType().getSimpleName();
                        Object actualValue = null;//真值
                        switch (propertySimpleType) {
                            case "byte", "Byte" -> actualValue = Byte.parseByte(value);
                            case "short", "Short" -> actualValue = Short.parseShort(value);
                            case "int", "Integer" -> actualValue = Integer.parseInt(value);
                            case "long", "Long" -> actualValue = Long.parseLong(value);
                            case "float", "Float" -> actualValue = Float.parseFloat(value);
                            case "double", "Double" -> actualValue = Double.parseDouble(value);
                            case "boolean", "Boolean" -> actualValue = Boolean.parseBoolean(value);
                            case "char", "Character" -> actualValue = value.charAt(0);
                            case "String" -> actualValue = value;
                            default -> {
                            }
                        }
                        setMethod.invoke(bean, actualValue);
                    } else if (null != ref) {
                        //说明这个值是非简单类型
                        Object resolveValue = getBean(ref);
                        //调用set方法(set方法没有返回值)
                        setMethod.invoke(bean, resolveValue);
                    }
    
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
            });
        }
    
        /**
         * 放入到三级缓存
         *
         * @param beanName
         * @param objectFactory 假设bean对象是工厂
         */
        public void addSingletonFactory(String beanName, Object objectFactory) {
            //将Bean曝光,放入Map集合
            singletonFactories.put(beanName, objectFactory);
            earlySingletonObjects.remove(beanName);
        }
    
        /**
         * 从缓存中获取bean
         *
         * @param beanName
         * @return
         */
        public Object getSingleton(String beanName) {
            Object bean = singletonObjects.get(beanName);
            if (null == bean) {
                bean = earlySingletonObjects.get(beanName);
                if (null == bean) {
                    bean = singletonFactories.get(beanName);
                    if (null != bean) {
                        singletonFactories.remove(beanName);
                        earlySingletonObjects.put(beanName, bean);
                    }
                }
            }
            return bean;
        }
    
        /**
         * 获取bean对象
         *
         * @param beanName myspring配置文件中bean标签的id
         * @return
         */
        @Override
        public Object getBean(String beanName) {
            Object bean = getSingleton(beanName);
            if (bean != null) {
                return bean;
            } else {
                doCreateBean(beanName);
                return singletonObjects.get(beanName);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245

    3、测试

    ABC

    @Data
    public class A {
        private String name;
        private B b;
        private C c;
    
        @Override
        public String toString() {
            return "A{" +
                    "name='" + name + '\'' +
                    ", b=" + b.getName() +
                    ", c=" + c.getName() +
                    '}';
        }
    }
    @Data
    class B {
        private C c;
        private A a;
        private String name;
    
    
        @Override
        public String toString() {
            return "B{" +
                    "c=" + c.getName() +
                    ", a=" + a.getName() +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    @Data
    class C {
        private String name;
        private B b;
        private A a;
    
        @Override
        public String toString() {
            return "C{" +
                    "name='" + name + '\'' +
                    ", b=" + b.getName() +
                    ", a=" + a.getName() +
                    '}';
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    myspring.xml

    
    <beans>
        <bean id="a" class="org.myspringframework.core.A">
            <property name="name" value="myName is a"/>
            <property name="b" ref="b"/>
            <property name="c" ref="c"/>
        bean>
        <bean id="b" class="org.myspringframework.core.B">
            <property name="name" value="myName is b"/>
            <property name="a" ref="a"/>
            <property name="c" ref="c"/>
        bean>
        <bean id="c" class="org.myspringframework.core.C">
            <property name="name" value="myName is c"/>
            <property name="a" ref="a"/>
            <property name="b" ref="b"/>
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    MyTest

    public class MyTest {
    
        @Test
        public void testMySpring() {
            ApplicationContext applicationContext = new ClasspathXmlApplicationContext("myspring.xml");
            A a = (A) applicationContext.getBean("a");
            B b = (B) applicationContext.getBean("b");
            C c = (C) applicationContext.getBean("c");
            System.out.println(a);
            System.out.println(b);
            System.out.println(c);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    结果

    image-20221114235827586

  • 相关阅读:
    etcd分布式存储
    JVM(Java Virtual Machine)G1收集器篇
    Redis为什么这么快?高频面试题详解
    idea 插件推荐第二期
    stm32——hal库学习笔记(ADC)
    〖大前端 - 基础入门三大核心之JS篇㊴〗- DOM节点的关系
    小程序如何获取code
    网络编程:socket的阻塞模式和非阻塞模式
    [Python学习笔记]Requests性能优化之Session
    wordpress制作主题步骤
  • 原文地址:https://blog.csdn.net/qq_67720621/article/details/127857818