手写spring+springmvc+mybatis框架篇【springIOC容器】

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

启动IOC容器为initBean方法。下面贴一下这两个类的关系图

首先是applicationContext

其次是InitBean

XmlApplicationContext :为解析xml文件的类,在spring源码中Resouce接口是用来解析多种文件格式的xml文件的接口,可能参数时inputStream,也可能是byteArray等,但是我们这里比较简单,直接用new File()传递xml文件。将读取到的对象用如下对象来保存

1
 Map<String, GenericBeanDefinition> beanDefinitionXmlMap = new ConcurrentHashMap<>(256);

spring也是这么做的。这个也就是我们说的容器。这里介绍一下我定义的这个beanDefinitionXmlMap 对象,beanDefinitionXmlMap 中的key为我们xml文件中的id,value为GenericBeanDefinition 对象,每一个GenericBeanDefinition 对象其实就代表一个bean,在GenericBeanDefinition 对象中,className就是对应的实体类的class的名字,而一个ChildBeanDefinition 对象就代表一个子元素(一个property:属性注入 或者一个constructor-arg元素:构造器注入)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package spring.factory;
 
import lombok.Data;
import java.util.List;
/**
 * Created by Xiao Liang on 2018/6/29.
 * 用来存放xml中注入的bean
 */
@Data
public class GenericBeanDefinition {
    /**
     * className和xml中的class对应
     */
    private String className;
 
    /**
     *  这是bean下面的属性集合
     */
    private List<ChildBeanDefinition> childBeanDefinitionList;
}
1
2
3
4
5
6
7
8
9
10
11
12
package spring.factory;
 
import lombok.Data;
/**
 * Created by Xiao Liang on 2018/6/27.
 */
@Data
public class ChildBeanDefinition {
    private String childrenType;// 这个是property或者constructor-arg类型
    private String attributeOne;//这个是第一个值
    private String attributeTwo;//这个是第二个值
}

我定义的IOCRULES是用枚举来表示的,下面贴一下我定义的注入规则。

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
package spring.xmlRules;
 
import lombok.Getter;
/**
 *  @Author xiao liang
 * Ioc中xml配置的规则
 */
@Getter
public enum IocRules {
    BEAN_RULE("bean", "id", "class"),
    SNAN_RULE("component-scan", "base-package", "null"),
    /**
     * set注入的规则
     */
    SET_INJECT("property", "name", "value"),
    /**
     * 构造器注入的规则,使用构造器注入的时候必须指定顺序。
     */
    CONS_INJECT("constructor-arg", "value", "index");
    private String type;
    private String name;
    private String value;
    IocRules(String property, String name, String value) {
        this.type  = property;
        this.name  = name;
        this.value = value;
    }
}

XmlApplicationContext:。其实这里最好是只提供接口,然后让子类来实现。但是为了简化,方便起见,直接写在了这里。最关键的是标红的两个方法,一个是getBeanDefinitionMap,一个是getComponentList。第一个是解析xml文件并且将属性值保存在容器(beanDefinitionXmlMap对象)中,第二个是获取一个链表,这个链表是存在注解扫描的并且排列好实例化顺序后的链表。这个扫描+实例化顺序的核心功能在ScanUtil工具类中。这个类也是难点。

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
package spring.xml;
 
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import spring.Utils.StringUtils;
import spring.Utils.scan.ScanUtil;
import spring.constants.Constants;
import spring.exception.XmlException;
import spring.factory.ChildBeanDefinition;
import spring.factory.GenericBeanDefinition;
import spring.xmlRules.IocRules;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * Created by Xiao Liang on 2018/6/28.
 * 封装解析xml的方法,模仿Ioc注入 BeanDefinition。实际注入的是GenericBeanDefinition
 */
@Slf4j
public class XmlApplicationContext {
    /**
     * @Description 将xml中的bean元素注入到容器中的方法
     *
     * @return 返回值是指定xml中的bean的容器
     */
    public  Map<String, GenericBeanDefinition> getBeanDefinitionMap(String contextConfigLocation) {
        Map<String, GenericBeanDefinition> beanDefinitionXmlMap = new ConcurrentHashMap<>(256);
        List<Element> elementsList = getElements(contextConfigLocation);
        //遍历每一个bean,注入beanDefinitionMap
        for (Element element :
                elementsList) {
            if (element.getName().equals("bean")){
                //声明一个bean的map,用来盛放当前bean子元素的容器
                GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
                List<ChildBeanDefinition> childBeanDefinitionList = new ArrayList<>();
                String beanId = element.attributeValue(IocRules.BEAN_RULE.getName());
                String beanClass = element.attributeValue(IocRules.BEAN_RULE.getValue());
                //保证子元素确实存在
                if (!StringUtils.isEmpty(beanId) && !StringUtils.isEmpty(beanClass)) {
                    //当前bean的className
                    genericBeanDefinition.setClassName(beanClass);
                    //当前bean的所有子元素
                    List<Element> elements = element.elements();
                    if (elements != null) {
                        for (Element childrenElement :
                                elements) {
                            //如果匹配set注入规则,则注入到容器
                            if (childrenElement.getName().equals(IocRules.SET_INJECT.getType())) {
                                ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition();
                                childBeanDefinition.setChildrenType(IocRules.SET_INJECT.getType());
                                String name = IocRules.SET_INJECT.getName();
                                String value = IocRules.SET_INJECT.getValue();
                                setChildBeanDefinitionByType(childrenElement, childBeanDefinition, name, value, childBeanDefinitionList);
                            }
                            //如果匹配构造器注入规则,则注入到容器
                            else if (childrenElement.getName().equals(IocRules.CONS_INJECT.getType())) {
                                ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition();
                                childBeanDefinition.setChildrenType(IocRules.CONS_INJECT.getType());
                                String name = IocRules.CONS_INJECT.getName();
                                String value = IocRules.CONS_INJECT.getValue();
                                setChildBeanDefinitionByType(childrenElement, childBeanDefinition, name, value, childBeanDefinitionList);
                            }
                        }
                    } else {
                        log.info("{}下面没有子元素", beanId);
                    }
                    genericBeanDefinition.setChildBeanDefinitionList(childBeanDefinitionList);
                    beanDefinitionXmlMap.put(beanId, genericBeanDefinition);
                }
            }
        }
        return beanDefinitionXmlMap;
    }
    /**
     * @Description 根据指定的xml,获得注解扫描的bean容器
     * @param contextConfigLocation
     * @return
     */
    public List<String> getComponentList(String contextConfigLocation){
        List<String> componentList = new ArrayList<>();
        List<Element> elementsList = getElements(contextConfigLocation);
        for (Element element :
                elementsList) {
            if (element.getName().equals(IocRules.SNAN_RULE.getType())) {
                String packageName = element.attributeValue(IocRules.SNAN_RULE.getName());
                componentList.addAll(resolveComponentList(packageName));
            }
        }
        return componentList;
    }
    /**
     * 根据要扫描的包名,返回有注解扫描的类
     * @param packageName
     * @return
     */
    public List<String> resolveComponentList(String packageName){
        if (StringUtils.isEmpty(packageName)){
            throw new XmlException("请正确设置"+IocRules.SNAN_RULE.getType()+"的属性");
        }
        List<String> componentList = new ArrayList<>();
        List<String> componentListAfter = ScanUtil.getComponentList(packageName);
        componentList.addAll(componentListAfter);
        return  componentList;
    }
    /**
     * 将每个bean的子元素注入容器
     *
     * @param element
     * @param childBeanDefinition
     * @param name
     * @param value
     * @param childBeanDefinitionList
     */
    private void setChildBeanDefinitionByType(Element element, ChildBeanDefinition childBeanDefinition, String name, String value,
                              List<ChildBeanDefinition> childBeanDefinitionList) {
        if (childBeanDefinition != null) {
            childBeanDefinition.setAttributeOne(element.attributeValue(name));
            childBeanDefinition.setAttributeTwo(element.attributeValue(value));
            childBeanDefinitionList.add(childBeanDefinition);
        } else {
            throw new XmlException("未按照格式配置xml文件或者暂不支持改配置属性");
        }
    }
 
    /**
     * 解析xml的工厂,根据路径名获取根元素下面的所有子元素
     * @param contextConfigLocation
     * @return
     */
    private List<Element> getElements(String contextConfigLocation) {
        // 创建saxReader对象
        SAXReader reader = new SAXReader();
        // 通过read方法读取一个文件 转换成Document对象
        Document document = null;
        String pathName = Constants.PATH + contextConfigLocation;
        try {
            document = reader.read(new File(pathName));
        } catch (DocumentException e) {
            log.error("文件没有找到,{}", pathName);
        }
        //获取根节点元素
        Element node = document.getRootElement();
        //获取所有的bean
        List<Element> elementsList = node.elements();
        return elementsList;
    }
}

难点一:ScanUtil类,这个类是spring容器的核心以及难点,我说一下过程,按照这个过程来看代码比较好理解。分为几个步骤

1 首先通过getClassName获取指定包下的所有类名的集合。

2 遍历每个类名的集合,用resolveComponent方法来扫描注解在类上的注解@MyController @MyService @MyRepository,

3 如果类上面有这些注解,则开始扫描此类上的属性上有没有@MyAutowired注解,如果存在@MyAutowired注解,则去属性对应的类上面递归上面的过程。直到类中没有@MyAutowired注解的时候。将类名添加到ComponentList链表中。在此过程中,如果类名是接口,并且有实现类的时候,添加到ComponentList链表中的是实现类的名字。为了完成此步骤,我设计了一个makeInterfaceAndImplMap方法用来绑定接口和其实现类,所以此框架目前只支持一个接口,一个实现类。

4 在第三步中,如果类上没有注解,并且是一个接口,此时默认是需要动态代理的接口,将此类名直接添加到ComponentList链表中。

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
package spring.Utils.scan;
 
import lombok.extern.slf4j.Slf4j;
import spring.Utils.AnnotationUtils;
import spring.Utils.ListAddUtils;
import spring.annotation.MyAutowired;
import spring.annotation.MyController;
import spring.annotation.MyRepository;
import spring.annotation.MyService;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
 * Created by Xiao Liang on 2018/6/27.
 * 扫描工具类(核心方法是getClassName和getComponentList)
 * 1 扫描包下的注解
 * 2 扫描包下的类名
 */
@Slf4j
public class ScanUtil {
    private static List<String> listClassName = new ArrayList<>();
    private static List<String> componentList = new ArrayList<>();
    private static Map<String, String> interfaceAndImplMap = new ConcurrentHashMap<>();
    /**
     * 扫描指定包下面的所有类名
     *
     * @param packageName,包名
     * @return 类名的集合,
     */
    public static List<String> getClassName(String packageName) {
        Enumeration<URL> urls = null;
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        String newPackageName = packageName.replace(".", "/");
        try {
            urls = contextClassLoader.getResources(newPackageName);
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                File packageFile = new File(url.getPath());
                File[] files = packageFile.listFiles();
                if (files == null) {
                    break;
                }
                for (File file :
                        files) {
                    //如果是class,则添加到list中返回
                    if (file.getName().endsWith(".class")) {
                        String templeName = (packageName.replace("/", ".") + "." + file.getName());
                        String newTempleName = templeName.substring(0, templeName.lastIndexOf("."));
                        listClassName.add(newTempleName);
                    }
                    //如果是package,则继续遍历
                    else {
                        String nextPackageName = newPackageName + "." + file.getName();
                        getClassName(nextPackageName);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return listClassName;
    }
    /**
     * 返回 有注解的实例化顺序的链表
     */
    public static List<String> getComponentList(String packageName) {
        //获取所有类
        List<String> classNameList = getClassName(packageName);
        //将扫描的接口和其实现类,使用map对应上,模仿spring接口注入,复杂的原因是java不支持从接口获取实现类
        makeInterfaceAndImplMap(classNameList);
        for (String className :
                classNameList) {
            try {
                //实例化每个类
                resolveComponent(className);
            } catch (ClassNotFoundException e) {
                log.error("扫描注解的时候,{}没有找到", className);
                e.printStackTrace();
            }
        }
        return componentList;
    }
    /**
     * getComponentList();递归调用的子方法
     *
     * @param className
     */
    public static void resolveComponent(String className) throws ClassNotFoundException {
        Class<?> aClass = Class.forName(className);
        //在此处添加要识别的注解,也是每次扫描的顺序,最好遵循习惯
        addNewAnnotation(MyController.class, aClass);
        addNewAnnotation(MyService.class, aClass);
        addNewAnnotation(MyRepository.class, aClass);
    }
    public static <A extends Annotation> void addNewAnnotation(Class<A> annotationClass, Class<?> aClass) throws ClassNotFoundException {
        //如果类上有注解,判断属性上有没有注解
        if (!AnnotationUtils.isEmpty(aClass.getAnnotation(annotationClass))) {
            Field[] fields = aClass.getDeclaredFields();
            if (fields == null || fields.length == 0) {
                ListAddUtils.add(componentList, aClass.getName());
            } else {
                //跳出递归的语句,也就是最底层的类,如果所有属性没有@MyAutowired注解,则注入到链表中
                if (isEmptyAutowired(fields)) {
                    ListAddUtils.add(componentList, aClass.getName());
                } else {
                    //如果属性上有@MyAutowired,则继续递归
                    for (Field field :
                            fields) {
                        //递归具体的查找到底哪个属性上有@MyAutowired。
                        if (field.getAnnotation(MyAutowired.class) != null) {
                            //如果有则根据类名查找类,然后去对应的类中递归此过程
                            String newFieldName = field.getType().getName();
                            //如果是接口,则用其实现类注入
                            if (Class.forName(newFieldName).isInterface()) {
                                String nextName = convertInterfaceToImpl(newFieldName);
                                if (!componentList.contains(nextName)) {
                                    resolveComponent(nextName);
                                }
                            } else {
                                resolveComponent(newFieldName);
                            }
                        }
                    }
                    ListAddUtils.add(componentList, aClass.getName());
                }
            }
        }
        //如果是需要动态的代理注入的接口,加入到实例化的链表中
        else if (aClass.isInterface() && interfaceAndImplMap.get(aClass.getName()).equals("proxy")) {
            ListAddUtils.add(componentList, aClass.getName());
        }
    }
    /**
     * 判断一组属性里面有没有注解
     *
     * @param fields
     * @return
     */
    private static boolean isEmptyAutowired(Field[] fields) {
        for (Field field :
                fields) {
            if (!AnnotationUtils.isEmpty(field.getAnnotation(MyAutowired.class))) {
                return false;
            }
        }
        return true;
    }
    /**
     * 工具类,组装接口和实现类
     *
     * @param classNameList
     * @return
     */
    private static Map<String, String> makeInterfaceAndImplMap(List<String> classNameList) {
        Class<?> aClass = null;
        //interfaceNameList是所有接口类名的链表
        List<String> interfaceNameList = new ArrayList<>();
        //这个链表保存的是有实现类的接口的链表名,默认没有实现类的接口即为需要动态注的链表
        List<String> interfaceExist = new ArrayList<>();
        //循环类名,将类名注入到链表中
        for (String className :
                classNameList) {
            try {
                aClass = Class.forName(className);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            if (aClass.isInterface()) {
                interfaceNameList.add(aClass.getName());
            }
        }
        for (String className :
                classNameList) {
            Class<?> bClass = null;
            try {
                bClass = Class.forName(className);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            Class<?>[] interfaces = bClass.getInterfaces();
            //如果是接口的实现类
            if (interfaces != null && interfaces.length != 0) {
                for (String interfaceName :
                        interfaceNameList) {
                    for (Class<?> interfaceClass :
                            interfaces) {
                        //如果既有接口,也有实现类,则组成map
                        if (interfaceName.equals(interfaceClass.getName())) {
                            interfaceAndImplMap.put(interfaceName, className);
                            interfaceExist.add(interfaceName);
                        }
                    }
                }
            }
        }
        //需要动态代理注入的接口,在map中用value = proxy来识别
        interfaceNameList.removeAll(interfaceExist);
        if (interfaceNameList != null && interfaceNameList.size() > 0) {
            for (String spareInterfaceName :
                    interfaceNameList) {
                interfaceAndImplMap.put(spareInterfaceName, "proxy");
            }
            System.out.println("已经存在的" + interfaceNameList);
        }
        return null;
    }
    /**
     * 工具类:接口转换为实现类
     *
     * @param newFileName
     * @return
     */
    private static String convertInterfaceToImpl(String newFileName) {
        Set<Map.Entry<String, String>> entries = interfaceAndImplMap.entrySet();
        for (Map.Entry<String, String> entry :
                entries) {
            if (newFileName.equals(entry.getKey()) && !entry.getValue().equals("proxy")) {
                return entry.getValue();
            } else if (newFileName.equals(entry.getKey()) && entry.getValue().equals("proxy")) {
                return entry.getKey();
            }
        }
        return null;
    }
}

这样获得实例化顺序的链表ComponentList之后,开始实例化,也就是initBean这个类。实例化通过反射new Instance()方法获得对象,绑定后的对象用beanContainerMap来保存,但是这里存在一个问题,就是我们动态代理添加到ComponentList的是接口名称,接口名称不能直接new Instance(),所以这里标红处用的是动态代理实例化的对象,这部分代码是针对Mybatis的接口注入的。先不用管具体是什么意思,后续会讲解。

这里还要注意的是先解析xml还是先解析注解扫描的问题,spring是优先解析xml文件的bean,然后执行的注解注入。和这里的顺序一致。

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
package spring.factory;
 
import lombok.extern.slf4j.Slf4j;
import spring.Utils.AnnotationUtils;
import spring.annotation.MyAutowired;
import spring.constants.Constants;
import spring.mybatis.MySqlSession;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
 * Created by Xiao Liang on 2018/6/27.
 */
@Slf4j
public class InitBean extends BeanDefinition {
    //初始化后的bean容器 key为class名,value为实例化对象
    public Map<String, Object> beanContainerMap = new ConcurrentHashMap<>();
    /**
     * 初始化bean容器方法
     * 注意,扫描的bean会覆盖xml中配置的bean,spring也是这样,扫描的注入和装配都是在xml之后
     * MyAutowired暂时是根据名称装配和扫描
     */
    public void initBeans() {
        //初始化xml配置
        initXmlBeans(Constants.contextConfigLocation);
        initXmlBeans(Constants.springmvcConfigLocation);
        //初始化扫描注解的配置
        initAutowiredBeans(Constants.contextConfigLocation);
    }
    /**
     * 初始化xml中bean内容的方法
     */
    public void initXmlBeans(String contextConfigLocation) {
        ApplicationContext applicationContext = new ApplicationContext(contextConfigLocation);
        Class<?> aClass = null;
        //从容器中取出bean,用application的getbean方法依次加载bean
        Map<String, GenericBeanDefinition> beanDefinitionMap = super.getbeanDefinitionXmlMap(contextConfigLocation);
        Set<Map.Entry<String, GenericBeanDefinition>> entries = beanDefinitionMap.entrySet();
        for (Map.Entry<String, GenericBeanDefinition> entry :
                entries) {
            String beanId = entry.getKey();
            String className = entry.getValue().getClassName();
            try {
                aClass = Class.forName(className);
 
            } catch (ClassNotFoundException e) {
                log.error("xml中{}无法实例化", className);
                e.printStackTrace();
            }
            beanContainerMap.put(className, aClass.cast(applicationContext.getBean(beanId)));
        }
    }
    /**
     * 将所有的componentList(也就是加注解的类)里面的bean实例化
     *
     * @return
     */
    public void initAutowiredBeans(String contextConfigLocation) {
        List<String> componentList = super.getComponentList(contextConfigLocation);
        System.out.println("实例化的顺序" + componentList);
        //扫描到有注解的类,初始化类的名单
        for (String className :
                componentList) {
            //将每一个类初始化
            try {
                initClass(className);
            } catch (ClassNotFoundException e) {
                log.error("{}没有找到", className);
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 初始化每一个类的方法,初始化的时候由于spring要实现使用接口注入,所以比较麻烦
     * 需要根据类名来判断是否有接口,然后在将接口名和实现类对应上装配到容器中
     *
     * @param className
     */
    public void initClass(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class<?> aClass = Class.forName(className);
        //先判断这个类有没有接口,如果有接口,将接口装配
        Class<?>[] interfaces = aClass.getInterfaces();
       //如果类是接口,注入的对象是动态代理的对象
        if (aClass.isInterface()){
            MySqlSession mySqlSession = new MySqlSession();
            beanContainerMap.put(aClass.getName(),mySqlSession.getMapper(aClass, Constants.mybatisConfigLocation));
        }
       //如果不是接口的实现类,也就是controller层
        else if (interfaces == null || interfaces.length == 0) {
            noInterfaceInit(className, className);
        }
        else {
            for (Class<?> interfaceClass :
                    interfaces) {
                boolean flag = isExistInContainer(className);
                //容器中如果有,则直接使用这个对象进行装配
                if (flag) {
                    beanContainerMap.put(interfaceClass.getName(), aClass.newInstance());
                } else {
                    //如果容器中没有,则先实例化实现类,然后再装配到容器中
                    noInterfaceInit(className, interfaceClass.getName());
                }
            }
        }
    }
    /**
     * @param className
     * @param interfaceName
     */
    public void noInterfaceInit(String className, String interfaceName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class<?> aClass = Class.forName(className);
        //bean实例化
        System.out.println("实例化的名字"+aClass.getName());
        Object object = aClass.newInstance();
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field field :
                declaredFields) {
            //如果属性上有MyAutowired注解,则先将属性注入进去
            if (!AnnotationUtils.isEmpty(field.getAnnotation(MyAutowired.class))) {
                //System.out.println("发现注解");
                //设置私有属性可见
                field.setAccessible(true);
                //如果有注解,在实例化链表里面搜寻类名
                Set<Map.Entry<String, Object>> entries = beanContainerMap.entrySet();
                for (Map.Entry<String, Object> entry :
                        entries) {
                    String type = field.getType().getName();
                    if (entry.getKey().equals(type)){
                        field.set(object, entry.getValue());
                    }
                }
            }
        }
        beanContainerMap.put(interfaceName, object);
    }
    /**
     * 属于工具类,不是很重要
     * 在实例化该类之前先判断该类在容器中是否存在
     *
     * @param className
     * @return
     */
    public boolean isExistInContainer(String className) {
        Set<Map.Entry<String, Object>> entries = beanContainerMap.entrySet();
        if (entries != null) {
            for (Map.Entry<String, Object> map :
                    entries) {
                if (map.getKey().equals(className)) {
                    return true;
                } else {
                    return false;
                }
            }
        }
        return false;
    }
}

至此,spring容器的开发暂时告一段落,下一篇介绍springmvc的实现。

我将此项目上传到了github,需要的童鞋可以自行下载。

https://github.com/836219171/MySSM