spring依赖注入原理


IOC(Inverse of Control)可翻译为“控制反转”,但大多数人都习惯将它称为“依赖注入”。在Spring中,通过IOC可以将实现类 、参数信息等配置在其对应的配置文件中 ,那么当需要更改实现类或参数信息时,只需要修改配置文件即可,这种方法在上例的基础上更进一步的降低了类与类之间的耦合。我们还可以对某对象所需要的其它对象进行注入 ,这种注入都是在配置文件中做的,Spring的IOC的实现原理利用的就是Java的反射机制,Spring还充当了工厂的角色,我们不需要自己建立工厂类 。Spring的工厂类会帮我们完成配置文件的读取、利用反射机制注入对象等工作,我们可以通过bean的名称获取对应的对象。下面让我们看看如下的模拟Spring的bean工厂类:

1、BeanFactory.java

Java代码
  1. packagecom.yt.manager.spring;
  2. importjava.io.InputStream;
  3. importjava.lang.reflect.Method;
  4. importjava.util.HashMap;
  5. importjava.util.Iterator;
  6. importjava.util.Map;
  7. importorg.apache.log4j.Logger;
  8. importorg.dom4j.Attribute;
  9. importorg.dom4j.Document;
  10. importorg.dom4j.Element;
  11. importorg.dom4j.io.SAXReader;
  12. /**
  13. *@ClassName:BeanFactory
  14. *@Project:base-info
  15. *@Author:zxf
  16. *@Date:2011-5-19
  17. */
  18. publicclassBeanFactory{
  19. Loggerlog=Logger.getLogger(BeanFactory.class);
  20. privateMap<String,Object>beanMap=newHashMap<String,Object>();
  21. /**
  22. *bean工厂的初始化
  23. *
  24. *@paramxml
  25. */
  26. publicvoidinit(Stringxml){
  27. try{
  28. //读取指定的配置文件
  29. SAXReaderreader=newSAXReader();
  30. //从class目录下获取指定的配置文件
  31. ClassLoaderclassLoader=Thread.currentThread().getContextClassLoader();
  32. InputStreaminputStream=classLoader.getResourceAsStream(xml);
  33. //读取xml文件
  34. Documentdocument=reader.read(inputStream);
  35. //获取跟节点
  36. Elementroot=document.getRootElement();
  37. //遍历bean节点
  38. Elementfoo;
  39. for(IteratoriteBean=root.elementIterator("bean");iteBean.hasNext();){
  40. foo=(Element)iteBean.next();
  41. //获取bean的属性id和class
  42. Attributeid=foo.attribute("id");
  43. Attributecls=foo.attribute("class");
  44. //利用java反射机制,通过class的名称获取Class对象
  45. Classbean=Class.forName(cls.getText());
  46. //获取对应class信息
  47. java.beans.BeanInfoinfo=java.beans.Introspector.getBeanInfo(bean);
  48. //获取其属性描述
  49. java.beans.PropertyDescriptorpd[]=info.getPropertyDescriptors();
  50. //设置值的方法
  51. MethodmSet=null;
  52. //创建一个对象(创建此Class对象所表示的类的一个新实例。如同用一个带有一个空参数列表的new表达式实例化该类。如果该类尚未初始化,则初始化这个类。)
  53. Objectobj=bean.newInstance();
  54. //遍历该bean的property属性
  55. for(IteratoriteProperty=foo.elementIterator("property");iteProperty.hasNext();){
  56. ElementelementProperty=(Element)iteProperty.next();
  57. //获取该property的name属性
  58. Attributename=elementProperty.attribute("name");
  59. Stringvalue=null;
  60. //获取该property的子元素value的值
  61. for(IteratoriteValue=elementProperty.elementIterator("value");iteValue.hasNext();){
  62. ElementelementValue=(Element)iteValue.next();
  63. value=elementValue.getText();
  64. break;
  65. }
  66. for(intk=0;k<pd.length;k++){
  67. log.info(pd[k].getName());
  68. if(pd[k].getName().equalsIgnoreCase(name.getText())){
  69. mSet=pd[k].getWriteMethod();
  70. //利用Java的反射机制调用对象的某个set方法,并将值设置进去
  71. mSet.invoke(obj,value);
  72. }
  73. }
  74. }
  75. //将对象放入beanMap中,其中key为id值,value为对象
  76. beanMap.put(id.getText(),obj);
  77. }
  78. }catch(Exceptione){
  79. e.printStackTrace();
  80. }
  81. }
  82. /**
  83. *通过bean的id获取bean的对象.
  84. *@parambeanNamebean的id
  85. *@return返回对应对象
  86. */
  87. publicObjectgetBean(StringbeanName){
  88. Objectobj=beanMap.get(beanName);
  89. returnobj;
  90. }
  91. publicstaticvoidmain(String[]args){
  92. BeanFactoryfactory=newBeanFactory();
  93. factory.init("config.xml");
  94. JavaBeanjavaBean=(JavaBean)factory.getBean("javaBean");
  95. System.out.println("userName="+javaBean.getUserName());
  96. System.out.println("password="+javaBean.getPassWord());
  97. }
  98. }

2、JavaBean.java

Java代码
  1. packagecom.yt.manager.spring;
  2. /**
  3. *@Description:
  4. *@ClassName:JavaBean
  5. *@Project:base-info
  6. *@Author:zxf
  7. *@Date:2011-5-19
  8. */
  9. publicclassJavaBean{
  10. privateStringuserName;
  11. privateStringpassWord;
  12. publicStringgetUserName(){
  13. returnuserName;
  14. }
  15. publicvoidsetUserName(StringuserName){
  16. this.userName=userName;
  17. }
  18. publicStringgetPassWord(){
  19. returnpassWord;
  20. }
  21. publicvoidsetPassWord(StringpassWord){
  22. this.passWord=passWord;
  23. }
  24. }

3、config.xml

Xml代码
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beans>
  3. <beanid="javaBean"class="com.yt.manager.spring.JavaBean">
  4. <propertyname="userName">
  5. <value>这是姓名</value>
  6. </property>
  7. <propertyname="passWord">
  8. <value>这是密码</value>
  9. </property>
  10. </bean>
  11. </beans>

可以看到,虽然在main()方法中没有对属性赋值,但属性值已经被注入,在BeanFactory类中的Class bean = Class.forName(cls.getText()); 通过类名来获取对应的类,mSet.invoke(obj, value);通过invoke方法来调用特定对象的特定方法,实现的原理都是基于Java的反射机制,在此我们有一次见证了Java反射机制的强大。当然,这只是对IOC的一个简单演示,在Spring中,情况要复杂得多,例如,可以一个bean引用另一个bean,还可以有多个配置文件、通过多种方式载入配置文件等等。不过原理还是采用Java的反射机制来实现IOC的。
在本文中,笔者通过讲述Java反射机制概述与初探、IOC使用的背景、IOC粉墨登场等内容,演示了Java反射机制API的强大功能,并通过编写自己的简单的IOC框架,让读者更好的理解了IOC的实现原理。本文通过IOC的一个简要实现实例,模拟了Spring中IOC的实现,虽然只是完成了Spring中依赖注入的一小部分工作, 但是很好的展现了Java反射机制在Spring中的应用,能使我们能更好的从原理上了解IOC的实现,也能为我们实现自己的准Spring框架提供方案,有兴趣的朋友可以通过Spring的源码进行IOC的进一步的学习。

附:通过java反射机制获取指定类的属性和方法

Java代码
  1. packagecom.yt.manager.spring;
  2. importjava.beans.BeanInfo;
  3. importjava.beans.Introspector;
  4. importjava.beans.MethodDescriptor;
  5. importjava.beans.PropertyDescriptor;
  6. /**
  7. *@Description:java.beans包的使用
  8. *@ClassName:JavaBeans
  9. *@Project:base-info
  10. *@Author:zxf
  11. *@Date:2011-5-19
  12. */
  13. publicclassJavaBeans{
  14. /**
  15. *@paramargs
  16. *@throwsException
  17. */
  18. @SuppressWarnings("rawtypes")
  19. publicstaticvoidmain(String[]args)throwsException{
  20. //返回与带有给定字符串名的类或接口相关联的Class对象
  21. Classbean=Class.forName("com.yt.manager.spring.JavaBean");
  22. //获取指定类的信息
  23. BeanInfoinfo=Introspector.getBeanInfo(bean);
  24. //遍历指定类的方法
  25. MethodDescriptor[]methods=info.getMethodDescriptors();
  26. for(inti=0;i<methods.length;i++){
  27. System.out.println("方法:"+methods[i].getDisplayName());
  28. }
  29. //遍历指定类的属性
  30. PropertyDescriptor[]propertys=info.getPropertyDescriptors();
  31. for(intj=0;j<propertys.length;j++){
  32. System.out.println("属性:"+propertys[j].getName());
  33. }
  34. }
  35. }

Java代码
  1. packagecom.yt.manager.spring;
  2. importjava.lang.reflect.Method;
  3. /**
  4. *@Description:java.lang.reflect.method类中invoke方法的使用
  5. *@ClassName:MethodInvoke
  6. *@Project:base-info
  7. *@Author:zxf
  8. *@Date:2011-5-19
  9. */
  10. publicclassMethodInvoke{
  11. /**
  12. *@paramargs
  13. *@throwsClassNotFoundException
  14. */
  15. publicstaticvoidmain(String[]args)throwsException{
  16. JavaBeanjavaBean=newJavaBean();
  17. //获取指定类的指定方法,
  18. Classc=Class.forName("com.yt.manager.spring.JavaBean");
  19. Methodmethod=c.getMethod("setUserName",newClass[]{String.class});
  20. //对带有指定参数的指定对象调用由此Method对象表示的底层方法,调用对象javaBean的setuserName方法,参数为"testName"
  21. method.invoke(javaBean,"testName");
  22. System.out.println(javaBean.getUserName());
  23. }
  24. }

优质内容筛选与推荐>>
1、AOSP 安卓源码7.1编译-真机运行
2、Delphi 获取指定文件的驱动器名, 文件夹名, 路径名, 文件名
3、优化前端网页性能
4、第二章 在HTML页面里使用javaScript
5、gl.TexSubImage2D 使用遇到图片翻转的问题


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn