(3) 利用 Setter方式实现 【第一种方式】 依赖注入,编码剖析Spring依赖注入的原理

  1. import cn.itm.dao.PersonDao;
  2. public class PersonDaoBean implements PersonDao {
  3. public void add(){
  4. System.out.println("执行PersonDaoBean的add方法。。。");
  5. }
  6. }



  1. package cn.itm.dao;
  2. public interface PersonDao {
  3. public abstract void add();
  4. }


  1. package cn.itm.service.impl;
  2. import cn.itm.dao.PersonDao;
  3. import cn.itm.service.PersonService;
  4. public class PersonServiceBean implements PersonService{
  5. // 使用 Set方法 是实现依赖注入:
  6. private PersonDao personDao;
  7. public void setPersonDao(PersonDao personDao) {
  8. this.personDao = personDao;
  9. }
  10. public void save(){
  11. // 调用 依赖对象注入进来的方法了。
  12. personDao.add();
  13. }
  14. }


  1. package cn.itm.service;
  2. public interface PersonService {
  3. public abstract void save();
  4. }

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  6. <bean id="personDao" class="cn.itm.dao.impl.PersonDaoBean"></bean>
  7. <bean id="personService" class="cn.itm.service.impl.PersonServiceBean" >
  8. <!-- 实现 注入 -->
  9. <property name="personDao" ref="personDao"></property>
  10. </bean>
  11. </beans>


测试类:

  1. package junit.test;
  2. import org.junit.BeforeClass;
  3. import org.junit.Test;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;
  6. import cn.itm.service.PersonService;
  7. public class SpringTest {
  8. @BeforeClass
  9. public static void setUpBeforeClass() throws Exception {
  10. }
  11. // 专门用来实例化 Spring 容器的。
  12. @Test public void instanceSpring(){
  13. ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
  14. PersonService personService = (PersonService) ctx.getBean("personService");
  15. personService.save();
  16. }
  17. }

成功。


利用setter方式的好处:可以被多个bean使用。



下面利用编码剖析Spring依赖注入的原理:


  1. package junit.test;
  2. import java.beans.Introspector;
  3. import java.beans.PropertyDescriptor;
  4. import java.lang.reflect.Method;
  5. import java.net.URL;
  6. import java.util.ArrayList;
  7. import java.util.HashMap;
  8. import java.util.List;
  9. import java.util.Map;
  10. import org.dom4j.Document;
  11. import org.dom4j.Element;
  12. import org.dom4j.XPath;
  13. import org.dom4j.io.SAXReader;
  14. public class ItmClassPathXMLApplicationContext {
  15. private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();
  16. // 存放实例
  17. private Map<String,Object> sigletons = new HashMap<String,Object>();
  18. public ItmClassPathXMLApplicationContext(String fileName){
  19. this.readXML(fileName);
  20. this.instanceBeans();
  21. this.injectObject();
  22. }
  23. private void injectObject() {
  24. for(BeanDefinition beanDefinition : beanDefines){
  25. // 得到 bean 。。
  26. Object bean = sigletons.get(beanDefinition.getId());
  27. if(bean != null){
  28. try {
  29. // 得到 bean的属性描述:
  30. PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
  31. // 循环 bean里面的 所有的属性:
  32. for( PropertyDefinition propertyDefinition: beanDefinition.getPropertys()){
  33. for(PropertyDescriptor propertyDesc /*这里是 bean 里面的属性*/ : ps){
  34. if(propertyDefinition.getName().equals(propertyDesc.getName())){
  35. // 如果相等 说明是存在 于 这个bean的。。。
  36. Method setter = propertyDesc.getWriteMethod(); // 获取属性的 setter方法。
  37. // 最好做一下判断:
  38. if(setter != null){
  39. Object value = sigletons.get(propertyDefinition.getRef());
  40. setter.setAccessible(true); // 允许访问 私有的方法。。
  41. setter.invoke(bean,value);// 把引用对象注入到属性。
  42. }
  43. break;
  44. }
  45. }
  46. }
  47. } catch (Exception e) {
  48. e.printStackTrace();
  49. }
  50. }
  51. }
  52. }
  53. /**
  54. * 通过反射技术,完成 bean 的实例化:
  55. */
  56. private void instanceBeans() {
  57. for(BeanDefinition beanDefinition : beanDefines){
  58. try {
  59. if(beanDefinition.getClassName() != null && !"".equals(beanDefinition.getClassName().trim())){
  60. sigletons.put(beanDefinition.getId(),Class.forName(beanDefinition.getClassName()).newInstance());
  61. }
  62. } catch (Exception e) {
  63. e.printStackTrace();
  64. }
  65. }
  66. }
  67. /**
  68. * 读取 XML 的配置文件:
  69. * @param fileName
  70. */
  71. @SuppressWarnings("unchecked")
  72. private void readXML(String fileName) {
  73. // 创建读取器:
  74. SAXReader saxReader = new SAXReader();
  75. Document document = null;
  76. try{
  77. URL xmlPath = this.getClass().getClassLoader().getResource(fileName);
  78. document = saxReader.read(xmlPath); // 读取文件的内容。。。
  79. Map<String,String> nsMap = new HashMap<String,String>();
  80. nsMap.put("ns","http://www.springframework.org/schema/beans"); // 加入命名空间
  81. // 创建beans/bean 查询路径。
  82. XPath xsub = document.createXPath("//ns:beans/ns:bean");
  83. // 设置命名空间。
  84. xsub.setNamespaceURIs(nsMap);
  85. // 获取文档下 所有bean节点:
  86. List<Element> beans = xsub.selectNodes(document);
  87. for(Element element : beans){
  88. String id = element.attributeValue("id"); // 获取id属性值。
  89. String clazz = element.attributeValue("class"); // 获取 class 属性值。
  90. BeanDefinition beanDefine = new BeanDefinition(id,clazz);
  91. // 查询的相对路径:
  92. XPath propertysub = element.createXPath("ns:property");
  93. propertysub.setNamespaceURIs(nsMap);// 设置命名空间。
  94. List<Element> propertys = propertysub.selectNodes(element);
  95. for(Element property : propertys){
  96. String propertyName = property.attributeValue("name");
  97. String propertyRef = property.attributeValue("ref");
  98. System.out.println(propertyName + "==" + propertyRef);
  99. PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName,propertyRef);
  100. // 放到 bean里面去:
  101. beanDefine.getPropertys().add(propertyDefinition);
  102. }
  103. beanDefines.add(beanDefine);
  104. }
  105. }catch(Exception e){
  106. e.printStackTrace();
  107. }
  108. }
  109. /**
  110. * 获取 bean实例
  111. * @param beanName
  112. * @return
  113. */
  114. public Object getBean(String beanName){
  115. return this.sigletons.get(beanName);
  116. }
  117. }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结