java控制反转与依赖注入

本是古典 何须时尚 2022-03-31 16:24 288阅读 0赞

1.简介

依赖注入和控制反转,目的是为了使类与类之间解耦合,提高系统的可扩展性和可维护性,下面通过一个例子来引入这一概念。

2.案例

1)一般情况下的类耦合

Main.java

  1. public class Main {
  2. public static void main(String[] args) {
  3. /******** 一般写法,Main类与Chinese类和American类之间的强耦合 ***********/
  4. // Chinese和American,当类和方法修改时,此处的类和方法也需要修改
  5. Chinese chinese = new Chinese();
  6. chinese.sayHelloWorld("张三");
  7. American american = new American();
  8. american.sayHelloWorld("Jack");
  9. }
  10. }
  11. /******************** 一般方法 ***************************/
  12. interface Human {
  13. public void sayHelloWorld(String name);
  14. }
  15. class Chinese implements Human {
  16. public void sayHelloWorld(String name) {
  17. String helloWorld = "你好," + name;
  18. System.out.println(helloWorld);
  19. }
  20. }
  21. class American implements Human {
  22. public void sayHelloWorld(String name) {
  23. String helloWorld = "Hello," + name;
  24. System.out.println(helloWorld);
  25. }
  26. }

通过上面代码可以看出:Main类与Chinese类和American类之间存在着强耦合 , Chinese和American类和方法修改时,此处的类和方法也需要修改。不容易扩展和维护。

2)工厂方法来解耦合

  1. public class Main {
  2. public static void main(String[] args) {
  3. /******** 工厂方法, Main类与类Chinese和American不再耦合,仅仅和其接口Human耦合 ***********/
  4. // 修改时还需要修改在Main类中修改这些字符串
  5. // Chinese和American,当类和方法修改时,只有方法需要修改
  6. HumanFactory humanFactory = new HumanFactory();
  7. Human human1 = humanFactory.getHuman("chinese");
  8. human1.sayHelloWorld("张三");
  9. Human human2 = humanFactory.getHuman("american");
  10. human2.sayHelloWorld("Jack");
  11. }
  12. }
  13. /******************** 工厂方法 ***************************/
  14. interface Human {
  15. public void sayHelloWorld(String name);
  16. }
  17. class HumanFactory {
  18. public Human getHuman(String type) {
  19. if ("chinese".equals(type)) {
  20. return new Chinese();
  21. } else {
  22. return new American();
  23. }
  24. }
  25. }

通过上面代码可以看出:Main类与类Chinese和American不再耦合,仅仅和其接口Human耦合,修改时还需要修改在Main类中 修改这些字符串,当类和方法修改时,只有方法需要修改。这一定程度上降低了Main类和Chinese、American类的耦合

3)依赖注入和控制反转

  1. public class Main {
  2. public static void main(String[] args) {
  3. /******************** IOC控制反转和依赖注入 ***************************/
  4. // 利用容器,通过xml文件直接注入属性值,在Main类中只添加需要的
  5. // Chinese和American,当类和方法修改时,代码完全不用修改,只需要修改xml文件即可,彻底实现了解耦
  6. BeanFactory beanFactory = new BeanFactory();
  7. beanFactory.init("/config.xml");
  8. UserBean userBean = (UserBean) beanFactory.getBean("userBean");
  9. System.out.println("userName=" + userBean.getUserName());
  10. System.out.println("password=" + userBean.getPassword());
  11. }
  12. }
  13. /******************** IOC控制反转和依赖注入 ***************************/
  14. // 下面是Spring的IOC实现:Bean工厂
  15. class BeanFactory {
  16. private Map<String, Object> beanMap = new HashMap<String, Object>();
  17. public void init(String fileName) {
  18. try {
  19. // 读取指定的配置文件
  20. SAXReader reader = new SAXReader();
  21. // System.out.println(xmlpath);
  22. String realPathString = new File("").getCanonicalPath();
  23. Document document = reader.read(new File(realPathString + "/src/com/devin/") + fileName);
  24. Element root = document.getRootElement();
  25. Element foo;
  26. // 遍历bean
  27. for (Iterator i = root.elementIterator("bean"); i.hasNext();) {
  28. foo = (Element) i.next();
  29. // 获取bean的属性id和class
  30. Attribute id = foo.attribute("id");
  31. Attribute cls = foo.attribute("class");
  32. // 利用Java反射机制,通过class的名称获取Class对象
  33. Class bean = Class.forName(cls.getText());
  34. // 获取对应class的信息
  35. java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean);
  36. // 获取其属性描述
  37. java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();
  38. // 设置值的方法
  39. Method mSet = null;
  40. // 创建一个对象
  41. Object obj = bean.newInstance();
  42. // 遍历该bean的property属性
  43. for (Iterator ite = foo.elementIterator("property"); ite.hasNext();) {
  44. Element foo2 = (Element) ite.next();
  45. // 获取该property的name属性
  46. Attribute name = foo2.attribute("name");
  47. String value = null;
  48. // 获取该property的子元素value的值
  49. for (Iterator ite1 = foo2.elementIterator("value"); ite1.hasNext();) {
  50. Element node = (Element) ite1.next();
  51. value = node.getText();
  52. break;
  53. }
  54. for (int k = 0; k < pd.length; k++) {
  55. if (pd[k].getName().equalsIgnoreCase(name.getText())) {
  56. mSet = pd[k].getWriteMethod();
  57. mSet.invoke(obj, value);
  58. }
  59. }
  60. }
  61. // 将对象放入beanMap中,其中key为id值,value为对象
  62. beanMap.put(id.getText(), obj);
  63. }
  64. } catch (Exception e) {
  65. System.out.println(e.toString());
  66. }
  67. }
  68. // 通过bean的id获取bean的对象.
  69. public Object getBean(String beanName) {
  70. Object obj = beanMap.get(beanName);
  71. return obj;
  72. }
  73. }
  74. UserBean.java
  75. public class UserBean {
  76. private String userName;
  77. private String password;
  78. public String getPassword() {
  79. return password;
  80. }
  81. public String getUserName() {
  82. return userName;
  83. }
  84. public void setUserName(String userName) {
  85. this.userName = userName;
  86. }
  87. public void setPassword(String password) {
  88. this.password = password;
  89. }
  90. }
  91. config.xml
  92. <?xml version="1.0" encoding="UTF-8"?>
  93. <beans>
  94. <bean id="userBean" class="com.devin.UserBean">
  95. <property name="userName">
  96. <value>张三</value>
  97. </property>
  98. <property name="password">
  99. <value>Jack</value>
  100. </property>
  101. </bean>
  102. </beans>

说明:模拟了Spring中IOC的实现,虽然只是完成了Spring中依赖注入的一小部分工作,但是很好的展现了Java反射机制在Spring中的应用,能使我们能更好的从原理上了解IOC的实现。

发表评论

表情:
评论列表 (有 0 条评论,288人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Spring的依赖注入控制

    平常的java开发中,如果某个类中需要依赖其它类的方法,通常是通过new一个依赖类,然后再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依