当前位置:   article > 正文

手写spring+springmvc+mybatis框架篇——springIOC容器_javaee中ioc容器封装map属性

javaee中ioc容器封装map属性

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

首先是applicationContext











其次是InitBean


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

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

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

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

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

  1. package spring.xmlRules;
  2. import lombok.Getter;
  3. /**
  4. * @Author xiao liang
  5. * Ioc中xml配置的规则
  6. */
  7. @Getter
  8. public enum IocRules {
  9. BEAN_RULE("bean", "id", "class"),
  10. SNAN_RULE("component-scan", "base-package", "null"),
  11. /**
  12. * set注入的规则
  13. */
  14. SET_INJECT("property", "name", "value"),
  15. /**
  16. * 构造器注入的规则,使用构造器注入的时候必须指定顺序。
  17. */
  18. CONS_INJECT("constructor-arg", "value", "index");
  19. private String type;
  20. private String name;
  21. private String value;
  22. IocRules(String property, String name, String value) {
  23. this.type = property;
  24. this.name = name;
  25. this.value = value;
  26. }
  27. }

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

  1. package spring.xml;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.dom4j.Document;
  4. import org.dom4j.DocumentException;
  5. import org.dom4j.Element;
  6. import org.dom4j.io.SAXReader;
  7. import spring.Utils.StringUtils;
  8. import spring.Utils.scan.ScanUtil;
  9. import spring.constants.Constants;
  10. import spring.exception.XmlException;
  11. import spring.factory.ChildBeanDefinition;
  12. import spring.factory.GenericBeanDefinition;
  13. import spring.xmlRules.IocRules;
  14. import java.io.File;
  15. import java.util.ArrayList;
  16. import java.util.List;
  17. import java.util.Map;
  18. import java.util.concurrent.ConcurrentHashMap;
  19. /**
  20. * Created by Xiao Liang on 2018/6/28.
  21. * 封装解析xml的方法,模仿Ioc注入 BeanDefinition。实际注入的是GenericBeanDefinition
  22. */
  23. @Slf4j
  24. public class XmlApplicationContext {
  25. /**
  26. * @Description 将xml中的bean元素注入到容器中的方法
  27. *
  28. * @return 返回值是指定xml中的bean的容器
  29. */
  30. public Map<String, GenericBeanDefinition> getBeanDefinitionMap(String contextConfigLocation) {
  31. Map<String, GenericBeanDefinition> beanDefinitionXmlMap = new ConcurrentHashMap<>(256);
  32. List<Element> elementsList = getElements(contextConfigLocation);
  33. //遍历每一个bean,注入beanDefinitionMap
  34. for (Element element :
  35. elementsList) {
  36. if (element.getName().equals("bean")){
  37. //声明一个bean的map,用来盛放当前bean子元素的容器
  38. GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
  39. List<ChildBeanDefinition> childBeanDefinitionList = new ArrayList<>();
  40. String beanId = element.attributeValue(IocRules.BEAN_RULE.getName());
  41. String beanClass = element.attributeValue(IocRules.BEAN_RULE.getValue());
  42. //保证子元素确实存在
  43. if (!StringUtils.isEmpty(beanId) && !StringUtils.isEmpty(beanClass)) {
  44. //当前bean的className
  45. genericBeanDefinition.setClassName(beanClass);
  46. //当前bean的所有子元素
  47. List<Element> elements = element.elements();
  48. if (elements != null) {
  49. for (Element childrenElement :
  50. elements) {
  51. //如果匹配set注入规则,则注入到容器
  52. if (childrenElement.getName().equals(IocRules.SET_INJECT.getType())) {
  53. ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition();
  54. childBeanDefinition.setChildrenType(IocRules.SET_INJECT.getType());
  55. String name = IocRules.SET_INJECT.getName();
  56. String value = IocRules.SET_INJECT.getValue();
  57. setChildBeanDefinitionByType(childrenElement, childBeanDefinition, name, value, childBeanDefinitionList);
  58. }
  59. //如果匹配构造器注入规则,则注入到容器
  60. else if (childrenElement.getName().equals(IocRules.CONS_INJECT.getType())) {
  61. ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition();
  62. childBeanDefinition.setChildrenType(IocRules.CONS_INJECT.getType());
  63. String name = IocRules.CONS_INJECT.getName();
  64. String value = IocRules.CONS_INJECT.getValue();
  65. setChildBeanDefinitionByType(childrenElement, childBeanDefinition, name, value, childBeanDefinitionList);
  66. }
  67. }
  68. } else {
  69. log.info("{}下面没有子元素", beanId);
  70. }
  71. genericBeanDefinition.setChildBeanDefinitionList(childBeanDefinitionList);
  72. beanDefinitionXmlMap.put(beanId, genericBeanDefinition);
  73. }
  74. }
  75. }
  76. return beanDefinitionXmlMap;
  77. }
  78. /**
  79. * @Description 根据指定的xml,获得注解扫描的bean容器
  80. * @param contextConfigLocation
  81. * @return
  82. */
  83. public List<String> getComponentList(String contextConfigLocation){
  84. List<String> componentList = new ArrayList<>();
  85. List<Element> elementsList = getElements(contextConfigLocation);
  86. for (Element element :
  87. elementsList) {
  88. if (element.getName().equals(IocRules.SNAN_RULE.getType())) {
  89. String packageName = element.attributeValue(IocRules.SNAN_RULE.getName());
  90. componentList.addAll(resolveComponentList(packageName));
  91. }
  92. }
  93. return componentList;
  94. }
  95. /**
  96. * 根据要扫描的包名,返回有注解扫描的类
  97. * @param packageName
  98. * @return
  99. */
  100. public List<String> resolveComponentList(String packageName){
  101. if (StringUtils.isEmpty(packageName)){
  102. throw new XmlException("请正确设置"+IocRules.SNAN_RULE.getType()+"的属性");
  103. }
  104. List<String> componentList = new ArrayList<>();
  105. List<String> componentListAfter = ScanUtil.getComponentList(packageName);
  106. componentList.addAll(componentListAfter);
  107. return componentList;
  108. }
  109. /**
  110. * 将每个bean的子元素注入容器
  111. *
  112. * @param element
  113. * @param childBeanDefinition
  114. * @param name
  115. * @param value
  116. * @param childBeanDefinitionList
  117. */
  118. private void setChildBeanDefinitionByType(Element element, ChildBeanDefinition childBeanDefinition, String name, String value,
  119. List<ChildBeanDefinition> childBeanDefinitionList) {
  120. if (childBeanDefinition != null) {
  121. childBeanDefinition.setAttributeOne(element.attributeValue(name));
  122. childBeanDefinition.setAttributeTwo(element.attributeValue(value));
  123. childBeanDefinitionList.add(childBeanDefinition);
  124. } else {
  125. throw new XmlException("未按照格式配置xml文件或者暂不支持改配置属性");
  126. }
  127. }
  128. /**
  129. * 解析xml的工厂,根据路径名获取根元素下面的所有子元素
  130. * @param contextConfigLocation
  131. * @return
  132. */
  133. private List<Element> getElements(String contextConfigLocation) {
  134. // 创建saxReader对象
  135. SAXReader reader = new SAXReader();
  136. // 通过read方法读取一个文件 转换成Document对象
  137. Document document = null;
  138. String pathName = Constants.PATH + contextConfigLocation;
  139. try {
  140. document = reader.read(new File(pathName));
  141. } catch (DocumentException e) {
  142. log.error("文件没有找到,{}", pathName);
  143. }
  144. //获取根节点元素
  145. Element node = document.getRootElement();
  146. //获取所有的bean
  147. List<Element> elementsList = node.elements();
  148. return elementsList;
  149. }
  150. }

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

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

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

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

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

  1. package spring.Utils.scan;
  2. import lombok.extern.slf4j.Slf4j;
  3. import spring.Utils.AnnotationUtils;
  4. import spring.Utils.ListAddUtils;
  5. import spring.annotation.MyAutowired;
  6. import spring.annotation.MyController;
  7. import spring.annotation.MyRepository;
  8. import spring.annotation.MyService;
  9. import java.io.File;
  10. import java.io.IOException;
  11. import java.lang.annotation.Annotation;
  12. import java.lang.reflect.Field;
  13. import java.net.URL;
  14. import java.util.*;
  15. import java.util.concurrent.ConcurrentHashMap;
  16. /**
  17. * Created by Xiao Liang on 2018/6/27.
  18. * 扫描工具类(核心方法是getClassName和getComponentList)
  19. * 1 扫描包下的注解
  20. * 2 扫描包下的类名
  21. */
  22. @Slf4j
  23. public class ScanUtil {
  24. private static List<String> listClassName = new ArrayList<>();
  25. private static List<String> componentList = new ArrayList<>();
  26. private static Map<String, String> interfaceAndImplMap = new ConcurrentHashMap<>();
  27. /**
  28. * 扫描指定包下面的所有类名
  29. *
  30. * @param packageName,包名
  31. * @return 类名的集合,
  32. */
  33. public static List<String> getClassName(String packageName) {
  34. Enumeration<URL> urls = null;
  35. ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
  36. String newPackageName = packageName.replace(".", "/");
  37. try {
  38. urls = contextClassLoader.getResources(newPackageName);
  39. while (urls.hasMoreElements()) {
  40. URL url = urls.nextElement();
  41. File packageFile = new File(url.getPath());
  42. File[] files = packageFile.listFiles();
  43. if (files == null) {
  44. break;
  45. }
  46. for (File file :
  47. files) {
  48. //如果是class,则添加到list中返回
  49. if (file.getName().endsWith(".class")) {
  50. String templeName = (packageName.replace("/", ".") + "." + file.getName());
  51. String newTempleName = templeName.substring(0, templeName.lastIndexOf("."));
  52. listClassName.add(newTempleName);
  53. }
  54. //如果是package,则继续遍历
  55. else {
  56. String nextPackageName = newPackageName + "." + file.getName();
  57. getClassName(nextPackageName);
  58. }
  59. }
  60. }
  61. } catch (IOException e) {
  62. e.printStackTrace();
  63. }
  64. return listClassName;
  65. }
  66. /**
  67. * 返回 有注解的实例化顺序的链表
  68. */
  69. public static List<String> getComponentList(String packageName) {
  70. //获取所有类
  71. List<String> classNameList = getClassName(packageName);
  72. //将扫描的接口和其实现类,使用map对应上,模仿spring接口注入,复杂的原因是java不支持从接口获取实现类
  73. makeInterfaceAndImplMap(classNameList);
  74. for (String className :
  75. classNameList) {
  76. try {
  77. //实例化每个类
  78. resolveComponent(className);
  79. } catch (ClassNotFoundException e) {
  80. log.error("扫描注解的时候,{}没有找到", className);
  81. e.printStackTrace();
  82. }
  83. }
  84. return componentList;
  85. }
  86. /**
  87. * getComponentList();递归调用的子方法
  88. *
  89. * @param className
  90. */
  91. public static void resolveComponent(String className) throws ClassNotFoundException {
  92. Class<?> aClass = Class.forName(className);
  93. //在此处添加要识别的注解,也是每次扫描的顺序,最好遵循习惯
  94. addNewAnnotation(MyController.class, aClass);
  95. addNewAnnotation(MyService.class, aClass);
  96. addNewAnnotation(MyRepository.class, aClass);
  97. }
  98. public static <A extends Annotation> void addNewAnnotation(Class<A> annotationClass, Class<?> aClass) throws ClassNotFoundException {
  99. //如果类上有注解,判断属性上有没有注解
  100. if (!AnnotationUtils.isEmpty(aClass.getAnnotation(annotationClass))) {
  101. Field[] fields = aClass.getDeclaredFields();
  102. if (fields == null || fields.length == 0) {
  103. ListAddUtils.add(componentList, aClass.getName());
  104. } else {
  105. //跳出递归的语句,也就是最底层的类,如果所有属性没有@MyAutowired注解,则注入到链表中
  106. if (isEmptyAutowired(fields)) {
  107. ListAddUtils.add(componentList, aClass.getName());
  108. } else {
  109. //如果属性上有@MyAutowired,则继续递归
  110. for (Field field :
  111. fields) {
  112. //递归具体的查找到底哪个属性上有@MyAutowired。
  113. if (field.getAnnotation(MyAutowired.class) != null) {
  114. //如果有则根据类名查找类,然后去对应的类中递归此过程
  115. String newFieldName = field.getType().getName();
  116. //如果是接口,则用其实现类注入
  117. if (Class.forName(newFieldName).isInterface()) {
  118. String nextName = convertInterfaceToImpl(newFieldName);
  119. if (!componentList.contains(nextName)) {
  120. resolveComponent(nextName);
  121. }
  122. } else {
  123. resolveComponent(newFieldName);
  124. }
  125. }
  126. }
  127. ListAddUtils.add(componentList, aClass.getName());
  128. }
  129. }
  130. }
  131. //如果是需要动态的代理注入的接口,加入到实例化的链表中
  132. else if (aClass.isInterface() && interfaceAndImplMap.get(aClass.getName()).equals("proxy")) {
  133. ListAddUtils.add(componentList, aClass.getName());
  134. }
  135. }
  136. /**
  137. * 判断一组属性里面有没有注解
  138. *
  139. * @param fields
  140. * @return
  141. */
  142. private static boolean isEmptyAutowired(Field[] fields) {
  143. for (Field field :
  144. fields) {
  145. if (!AnnotationUtils.isEmpty(field.getAnnotation(MyAutowired.class))) {
  146. return false;
  147. }
  148. }
  149. return true;
  150. }
  151. /**
  152. * 工具类,组装接口和实现类
  153. *
  154. * @param classNameList
  155. * @return
  156. */
  157. private static Map<String, String> makeInterfaceAndImplMap(List<String> classNameList) {
  158. Class<?> aClass = null;
  159. //interfaceNameList是所有接口类名的链表
  160. List<String> interfaceNameList = new ArrayList<>();
  161. //这个链表保存的是有实现类的接口的链表名,默认没有实现类的接口即为需要动态注的链表
  162. List<String> interfaceExist = new ArrayList<>();
  163. //循环类名,将类名注入到链表中
  164. for (String className :
  165. classNameList) {
  166. try {
  167. aClass = Class.forName(className);
  168. } catch (ClassNotFoundException e) {
  169. e.printStackTrace();
  170. }
  171. if (aClass.isInterface()) {
  172. interfaceNameList.add(aClass.getName());
  173. }
  174. }
  175. for (String className :
  176. classNameList) {
  177. Class<?> bClass = null;
  178. try {
  179. bClass = Class.forName(className);
  180. } catch (ClassNotFoundException e) {
  181. e.printStackTrace();
  182. }
  183. Class<?>[] interfaces = bClass.getInterfaces();
  184. //如果是接口的实现类
  185. if (interfaces != null && interfaces.length != 0) {
  186. for (String interfaceName :
  187. interfaceNameList) {
  188. for (Class<?> interfaceClass :
  189. interfaces) {
  190. //如果既有接口,也有实现类,则组成map
  191. if (interfaceName.equals(interfaceClass.getName())) {
  192. interfaceAndImplMap.put(interfaceName, className);
  193. interfaceExist.add(interfaceName);
  194. }
  195. }
  196. }
  197. }
  198. }
  199. //需要动态代理注入的接口,在map中用value = proxy来识别
  200. interfaceNameList.removeAll(interfaceExist);
  201. if (interfaceNameList != null && interfaceNameList.size() > 0) {
  202. for (String spareInterfaceName :
  203. interfaceNameList) {
  204. interfaceAndImplMap.put(spareInterfaceName, "proxy");
  205. }
  206. System.out.println("已经存在的" + interfaceNameList);
  207. }
  208. return null;
  209. }
  210. /**
  211. * 工具类:接口转换为实现类
  212. *
  213. * @param newFileName
  214. * @return
  215. */
  216. private static String convertInterfaceToImpl(String newFileName) {
  217. Set<Map.Entry<String, String>> entries = interfaceAndImplMap.entrySet();
  218. for (Map.Entry<String, String> entry :
  219. entries) {
  220. if (newFileName.equals(entry.getKey()) && !entry.getValue().equals("proxy")) {
  221. return entry.getValue();
  222. } else if (newFileName.equals(entry.getKey()) && entry.getValue().equals("proxy")) {
  223. return entry.getKey();
  224. }
  225. }
  226. return null;
  227. }
  228. }

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

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

  1. package spring.factory;
  2. import lombok.extern.slf4j.Slf4j;
  3. import spring.Utils.AnnotationUtils;
  4. import spring.annotation.MyAutowired;
  5. import spring.constants.Constants;
  6. import spring.mybatis.MySqlSession;
  7. import java.lang.reflect.Field;
  8. import java.util.List;
  9. import java.util.Map;
  10. import java.util.Set;
  11. import java.util.concurrent.ConcurrentHashMap;
  12. /**
  13. * Created by Xiao Liang on 2018/6/27.
  14. */
  15. @Slf4j
  16. public class InitBean extends BeanDefinition {
  17. //初始化后的bean容器 key为class名,value为实例化对象
  18. public Map<String, Object> beanContainerMap = new ConcurrentHashMap<>();
  19. /**
  20. * 初始化bean容器方法
  21. * 注意,扫描的bean会覆盖xml中配置的bean,spring也是这样,扫描的注入和装配都是在xml之后
  22. * MyAutowired暂时是根据名称装配和扫描
  23. */
  24. public void initBeans() {
  25. //初始化xml配置
  26. initXmlBeans(Constants.contextConfigLocation);
  27. initXmlBeans(Constants.springmvcConfigLocation);
  28. //初始化扫描注解的配置
  29. initAutowiredBeans(Constants.contextConfigLocation);
  30. }
  31. /**
  32. * 初始化xml中bean内容的方法
  33. */
  34. public void initXmlBeans(String contextConfigLocation) {
  35. ApplicationContext applicationContext = new ApplicationContext(contextConfigLocation);
  36. Class<?> aClass = null;
  37. //从容器中取出bean,用application的getbean方法依次加载bean
  38. Map<String, GenericBeanDefinition> beanDefinitionMap = super.getbeanDefinitionXmlMap(contextConfigLocation);
  39. Set<Map.Entry<String, GenericBeanDefinition>> entries = beanDefinitionMap.entrySet();
  40. for (Map.Entry<String, GenericBeanDefinition> entry :
  41. entries) {
  42. String beanId = entry.getKey();
  43. String className = entry.getValue().getClassName();
  44. try {
  45. aClass = Class.forName(className);
  46. } catch (ClassNotFoundException e) {
  47. log.error("xml中{}无法实例化", className);
  48. e.printStackTrace();
  49. }
  50. beanContainerMap.put(className, aClass.cast(applicationContext.getBean(beanId)));
  51. }
  52. }
  53. /**
  54. * 将所有的componentList(也就是加注解的类)里面的bean实例化
  55. *
  56. * @return
  57. */
  58. public void initAutowiredBeans(String contextConfigLocation) {
  59. List<String> componentList = super.getComponentList(contextConfigLocation);
  60. System.out.println("实例化的顺序" + componentList);
  61. //扫描到有注解的类,初始化类的名单
  62. for (String className :
  63. componentList) {
  64. //将每一个类初始化
  65. try {
  66. initClass(className);
  67. } catch (ClassNotFoundException e) {
  68. log.error("{}没有找到", className);
  69. e.printStackTrace();
  70. } catch (IllegalAccessException e) {
  71. e.printStackTrace();
  72. } catch (InstantiationException e) {
  73. e.printStackTrace();
  74. }
  75. }
  76. }
  77. /**
  78. * 初始化每一个类的方法,初始化的时候由于spring要实现使用接口注入,所以比较麻烦
  79. * 需要根据类名来判断是否有接口,然后在将接口名和实现类对应上装配到容器中
  80. *
  81. * @param className
  82. */
  83. public void initClass(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
  84. Class<?> aClass = Class.forName(className);
  85. //先判断这个类有没有接口,如果有接口,将接口装配
  86. Class<?>[] interfaces = aClass.getInterfaces();
  87. //如果类是接口,注入的对象是动态代理的对象
  88. if (aClass.isInterface()){
  89. MySqlSession mySqlSession = new MySqlSession();
  90. beanContainerMap.put(aClass.getName(),mySqlSession.getMapper(aClass, Constants.mybatisConfigLocation));
  91. }
  92. //如果不是接口的实现类,也就是controller层
  93. else if (interfaces == null || interfaces.length == 0) {
  94. noInterfaceInit(className, className);
  95. }
  96. else {
  97. for (Class<?> interfaceClass :
  98. interfaces) {
  99. boolean flag = isExistInContainer(className);
  100. //容器中如果有,则直接使用这个对象进行装配
  101. if (flag) {
  102. beanContainerMap.put(interfaceClass.getName(), aClass.newInstance());
  103. } else {
  104. //如果容器中没有,则先实例化实现类,然后再装配到容器中
  105. noInterfaceInit(className, interfaceClass.getName());
  106. }
  107. }
  108. }
  109. }
  110. /**
  111. * @param className
  112. * @param interfaceName
  113. */
  114. public void noInterfaceInit(String className, String interfaceName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
  115. Class<?> aClass = Class.forName(className);
  116. //bean实例化
  117. System.out.println("实例化的名字"+aClass.getName());
  118. Object object = aClass.newInstance();
  119. Field[] declaredFields = aClass.getDeclaredFields();
  120. for (Field field :
  121. declaredFields) {
  122. //如果属性上有MyAutowired注解,则先将属性注入进去
  123. if (!AnnotationUtils.isEmpty(field.getAnnotation(MyAutowired.class))) {
  124. //System.out.println("发现注解");
  125. //设置私有属性可见
  126. field.setAccessible(true);
  127. //如果有注解,在实例化链表里面搜寻类名
  128. Set<Map.Entry<String, Object>> entries = beanContainerMap.entrySet();
  129. for (Map.Entry<String, Object> entry :
  130. entries) {
  131. String type = field.getType().getName();
  132. if (entry.getKey().equals(type)){
  133. field.set(object, entry.getValue());
  134. }
  135. }
  136. }
  137. }
  138. beanContainerMap.put(interfaceName, object);
  139. }
  140. /**
  141. * 属于工具类,不是很重要
  142. * 在实例化该类之前先判断该类在容器中是否存在
  143. *
  144. * @param className
  145. * @return
  146. */
  147. public boolean isExistInContainer(String className) {
  148. Set<Map.Entry<String, Object>> entries = beanContainerMap.entrySet();
  149. if (entries != null) {
  150. for (Map.Entry<String, Object> map :
  151. entries) {
  152. if (map.getKey().equals(className)) {
  153. return true;
  154. } else {
  155. return false;
  156. }
  157. }
  158. }
  159. return false;
  160. }
  161. }

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

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

https://github.com/836219171/MySSM


本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号