简单的说,Spring就是通过工厂+反射将我们的bean放到它的容器中的,当我们想用某个bean的时候,只需要调用getBean("beanID")方法即可。

原理简单说明:

Spring容器的原理,其实就是通过解析xml文件,通过反射创建出我们所需要的bean,再将这些bean挨个放到集合中,然后对外提供一个getBean()方法,以便我们获得这bean。

下面我们来简单实现一个demo

beans.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans>
  3. <bean id="user" class="com.yyb.model.User" />
  4. <bean id="userDAO" class="com.yyb.dao.impl.UserDAOImpl" />
  5. <bean id="userService" class="com.yyb.service.UserService">
  6. <property name="userDAO" bean="userDAO" />
  7. </bean>
  8. </beans>

BeanFactory

  1. public interface BeanFactory {
  2. Object getBean(String name);
  3. }

ClassPathXmlApplicationContext:读取xml文件内容,并创建对象及对象关系(使用setter方式)

  1. package com.yyb.spring;
  2. import java.io.IOException;
  3. import java.lang.reflect.InvocationTargetException;
  4. import java.lang.reflect.Method;
  5. import java.util.HashMap;
  6. import java.util.List;
  7. import java.util.Map;
  8. import org.jdom.Document;
  9. import org.jdom.Element;
  10. import org.jdom.JDOMException;
  11. import org.jdom.input.SAXBuilder;
  12. public class ClassPathXmlApplicationContext implements BeanFactory
  13. {
  14. private Map<String, Object> beans = new HashMap<String, Object>();
  15. public ClassPathXmlApplicationContext() throws JDOMException, IOException,
  16. InstantiationException, IllegalAccessException,
  17. ClassNotFoundException, SecurityException, NoSuchMethodException,
  18. IllegalArgumentException, InvocationTargetException
  19. {
  20. SAXBuilder sb = new SAXBuilder();
  21. // 构造文档对象
  22. Document doc = sb.build(ClassPathXmlApplicationContext.class
  23. .getClassLoader().getResourceAsStream("beans.xml"));
  24. // 获取根元素
  25. Element root = doc.getRootElement();
  26. // 取到根元素所有元素
  27. List list = root.getChildren();
  28. for (int i = 0; i < list.size(); i++)
  29. {
  30. Element element = (Element) list.get(i);
  31. // 取id子元素
  32. String beanid = element.getAttributeValue("id");
  33. // 取class子元素
  34. String clzss = element.getAttributeValue("class");
  35. // 实例化
  36. Object o = Class.forName(clzss).newInstance();
  37. // 将所有bean放入map中
  38. beans.put(beanid, o);
  39. // 获取property 进行依赖注入
  40. for (Element propertyElement : (List<Element>) element
  41. .getChildren("property"))
  42. {
  43. String name = propertyElement.getAttributeValue("name");
  44. System.out.println(name);//userDAO
  45. String bean = propertyElement.getAttributeValue("bean");
  46. System.out.println(bean);//userDAO
  47. // 从beans.xml中根据id取到类的对象
  48. //Object beanObj = this.getBean(name);
  49. // 从beans.xml中根据id取到类的对象
  50. Object beanObj = this.getBean(bean);
  51. System.out.println(beanObj);//com.yyb.dao.impl.UserDAOImpl@a09ee92
  52. // 形成setXXX方法名
  53. String methodName = "set" + name.substring(0, 1).toUpperCase()
  54. + name.substring(1);
  55. System.out.println(name.substring(0, 1).toUpperCase());//U
  56. System.out.println(name.substring(1));//serDAO
  57. System.out.println(methodName);//setUserDAO
  58. // 反射机制对方法进行调用,将对象在加载bean时就注入到环境上下文中
  59. Method m = o.getClass().getMethod(methodName,
  60. beanObj.getClass().getInterfaces()[0]);
  61. System.out.println(o.getClass());//class com.yyb.service.UserService
  62. System.out.println(beanObj.getClass().getInterfaces()[0]);//interface com.yyb.dao.UserDAO
  63. System.out.println(m);//public void com.yyb.service.UserService.setUserDAO(com.yyb.dao.UserDAO)
  64. // 执行注入,相当于执行了一个setXXX(args..)的方法
  65. m.invoke(o, beanObj);
  66. }
  67. }
  68. }
  69. @Override
  70. public Object getBean(String name)
  71. {
  72. return beans.get(name);
  73. }
  74. }

对于以上这段代码实现的效果为:

Service service=(Service)beans.get("userService");

Dao dao = (Dao)beans.get("userDAO");

//依赖注入,Service实现依赖dao的实现

service.setDao(dao);

User:实体类

  1. public class User {
  2. private String userName;
  3. private String password;
  4. /**
  5. * @return the userName
  6. */
  7. public String getUserName()
  8. {
  9. return userName;
  10. }
  11. /**
  12. * @param userName
  13. *            the userName to set
  14. */
  15. public void setUserName(String userName)
  16. {
  17. this.userName = userName;
  18. }
  19. /**
  20. * @return the password
  21. */
  22. public String getPassword()
  23. {
  24. return password;
  25. }
  26. /**
  27. * @param password
  28. *  the password to set
  29. */
  30. public void setPassword(String password)
  31. {
  32. this.password = password;
  33. }
  34. public String toString()
  35. {
  36. StringBuffer sb = new StringBuffer();
  37. sb.append(this.userName);
  38. sb.append(this.password);
  39. return sb.toString();
  40. }
  41. }

UserDAO

  1. public interface UserDAO {
  2. void save(User u);
  3. void delete();
  4. }

UserDAOImpl

  1. public class UserDAOImpl implements UserDAO {
  2. @Override
  3. public void save(User u) {
  4. System.out.println("User:" + u.toString());
  5. }
  6. @Override
  7. public void delete() {
  8. System.out.println("delete User");
  9. }
  10. }

UserService

  1. public class UserService {
  2. private UserDAO userDAO;
  3. public void addUser(User u)
  4. {
  5. this.userDAO.save(u);
  6. }
  7. /**
  8. * @return the userDAO
  9. */
  10. public UserDAO getUserDAO()
  11. {
  12. return userDAO;
  13. }
  14. /**
  15. * @param userDAO
  16. *            the userDAO to set
  17. */
  18. public void setUserDAO(UserDAO userDAO)
  19. {
  20. this.userDAO = userDAO;
  21. }
  22. }

下面我们来简单测试一下实现的效果:

Client

  1. public class client {
  2. public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException, JDOMException, IOException {
  3. BeanFactory factory = new ClassPathXmlApplicationContext();
  4. //通过工厂直接获取
  5. UserService userService = (UserService) factory.getBean("userService");
  6. //其实User也可以从工厂中获得
  7. User u=(User)factory.getBean("user");
  8. //User u = new User();
  9. u.setUserName("yyb");
  10. u.setPassword("1234");
  11. userService.addUser(u);//打印结果yyb1234
  12. }
  13. }

当然以上我们是通过setter方法注入,还可以使用构造器注入,也就是在建立对象的时候建立关系(即在UserService的构造函数中添加对userDAO的赋值操作)

总结:

以上通过IOC的一个简要实现实例,模拟了Spring中IOC的实现,虽然只是完成了Spring中依赖注入的一小部分工作,但是很好的展现了Java反射机制在Spring中的应用,能使我们能更好的从原理上了解IOC的实现,也能为我们实现自己的Spring框架提供了方案。

Spring IOC实现原理demo:IOC

Spring IOC的简单实现的更多相关文章

  1. Spring IOC 的简单使用

    Spring IOC (Inversion Of Control反转控制容器 一.对于IOC容器的简单理解 在java开发中将程序中的对象交给容器管理,而不是在对象的内部管理. 那么两个简单的问题去分 ...

  2. Spring IOC 方式结合TESTGN测试用例,测试简单java的命令模式

    java命令模式: 可以命令("请求")封装成一个对象,一个命令对象通过在特定的接收着上绑定一组动作来封装一个请求.命令对象直接把执行动作和接收者包进对象中,只对外暴露出执行方法的 ...

  3. 1.Spring IoC简单例子

    Spring IoC简单例子 1.IHelloMessage.java package com.tony.spring.chapter01; public interface IHelloMessag ...

  4. Spring容器的简单实现(IOC原理)

    引言:容器是什么?什么是容器?Spring容器又是啥东西?我给Spring容器一个对象名字,为啥能给我创建一个对象呢? 一.容器是装东西的,就像你家的水缸,你吃饭的碗等等. java中能作为容器的有很 ...

  5. Spring IOC 源码简单分析 03 - 循环引用

    ### 准备 ## 目标 了解 Spring 如何处理循环引用 ##测试代码 gordon.study.spring.ioc.IOC03_CircularReference.java   ioc03. ...

  6. Spring IOC 源码简单分析 02 - Bean Reference

    ### 准备 ## 目标 了解 bean reference 装配的流程 ##测试代码 gordon.study.spring.ioc.IOC02_BeanReference.java   ioc02 ...

  7. (反射+内省机制的运用)简单模拟spring IoC容器的操作

    简单模拟spring IoC容器的操作[管理对象的创建.管理对象的依赖关系,例如属性设置] 实体类Hello package com.shan.hello; public class Hello { ...

  8. spring IOC简单分析

    Spring IOC 体系结构 BeanFactory(BeanFactory 里只对 IOC 容器的基本行为作了定义,根本不关心你的 bean 是如何定义怎样加载的.正如我们只关心工厂里得到什么的产 ...

  9. Spring IOC 源码简单分析 04 - bean的初始化

      ### 准备 ## 目标 了解 Spring 如何初始化 bean 实例 ##测试代码 gordon.study.spring.ioc.IOC04_Initialization.java publ ...

随机推荐

  1. ASP.NET Core-Docs:在 ASP.NET Core 中启用跨域请求(CORS)

    ylbtech-ASP.NET Core-Docs:在 ASP.NET Core 中启用跨域请求(CORS) 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部 1. ...

  2. Jenkins笔录

    1.Linux下安装jdk8的方法 ,只需要一条命令就可以安装jdk: yum install java-1.8.0-openjdk* -y 执行过这条命令无需配置,直接可以使用. 2.JDK12版本 ...

  3. jQuery选择:子代元素与后代元素的区别

    (1)后代元素:html代码如下,那么在jquery选择时,$(".test img"),中间为空格,则是选取后代元素,img对于ul来说是孙子辈元素,中间隔了li元素,所以后代元 ...

  4. Mysql:常用操作(导入数据,用户授权,远程连接授权,设置通信缓冲区的最大长度)

    1.导入数据命令: mysql --host=localhost --port=3306 --user=root --password=hnsjt_lwsj@2018 szyszx_20180515- ...

  5. java安全停止线程

    Thread.stop()是一个被废弃的方法,不被推荐使用的原因是stop方法太过于暴力,强行把执行到一半的线程终止,并且会立即释放这个线程所有的锁.会破坏了线程中引用对象的一致性. 使用判断标志位的 ...

  6. zabbix支持的主要监控方式

    一.zabbix支持的主要监控方式: zabbix主要Agent,Trapper,SNMP,JMX,IPMI这几种监控方式,本文章主要通过监控理论和实际操作测试等方式来简单介绍这几种方式的监控原理和优 ...

  7. 【机器学习】Jackknife,Bootstraping, bagging, boosting, AdaBoosting, Rand forest 和 gradient boosting

    Jackknife,Bootstraping, bagging, boosting, AdaBoosting, Rand forest 和 gradient boosting 这些术语,我经常搞混淆, ...

  8. 【DSP开发】【Linux开发】IIC设备驱动程序

    IIC设备是一种通过IIC总线连接的设备,由于其简单性,被广泛引用于电子系统中.在现代电子系统中,有很多的IIC设备需要进行相互之间通信 IIC总线是由PHILIPS公司开发的两线式串行总线,用于连接 ...

  9. eclipse -------导出war包

    1.右键工程名--Export----- WAR file 2.输入war包名,选择导出路径,finish完成

  10. WinForm笔记1:TextBox编辑时和DataGridView 单元格编辑时 的事件及其顺序

    TextBox 编辑框 When you change the focus by using the mouse or by calling the Focus method, focus event ...