`
jackmisweijie
  • 浏览: 72001 次
  • 性别: Icon_minigender_1
  • 来自: 河南
社区版块
存档分类
最新评论

第二章 深入探讨控制反转(Ioc)和依赖注入(DI)

 
阅读更多

 注:希望大家看后,请给我一点评价,无论写的怎么样,希望你们能给我支持。提出你宝贵的意见。我会继续完善。谢谢您。朋友。

第二章 深入探讨控制反转(Ioc)和依赖注入(DI
在第一章中已经对控制反转(Ioc)和依赖注入(DI)有了一个初步的了解,现在让我们通过具体的程序代码来真正的体验一下,它们真的有那么神奇吗?
在演练之前,我还要先讲一下理论知识,然后在演练程序代码。让你也体会到其中的神奇效果。
Spring 中的控制反转(IoC
1IoC = Inversion of Control(由容器控制程序之间的关系)
IoC,用白话来讲,就是由容器来控制程序中的各个类之间的关系,而非传统实现中,直接在代码中由程序代码直接操控。比如在一个类(A)中访问另外一个类中(B)的方法时,我们需要先去new 一个B的对象,然后调用所需的方法。他们的关系很显然在程序代码中控制,同时它们之间的耦合度也比较大,不利于代码的重用。而我们现在把这种控制程序之间的关系交给Ioc容器,让它去帮你实例化你所需要的对象,而你直接在程序中调用就可以了。这也就是所谓"控制反转"的概念的由来:控制权由应用程序的代码中转到了外部容器,控制权的转移,是所谓反转的由来
可能你不知道Ioc容器到底,或确切的指的是什么?其实这里的容器就相当于一个工厂一样。你需要什么,直接来拿,直接用就可以了,而不需要去了解,去关心你所用的东西是如何制成的,在程序中体现为实现的细节,这里就用到了工厂模式,其实Spring容器就是工厂模式和单例模式所实现的。在第三章中我将会详细介绍SpringIoc容器。
对于初学者,我想简单的先说明几点,不要把applicationContext.xml,或带有bean的配置文件理解为容器,它们只是描述了要用到的类(bean)之间的依赖关系。Spring中的容器很抽象,不像Tomcat,Weblogic,WebSphere等那样的应用服务器容器是可见的。SpringIoc容器给人的感觉好像就是那些配置文件(applicationContext.xml,我刚开始学时,也以为就是那些带bean的配置文件,虽然它对你学习Spring没什么影响,但如果想更深沉的了解就会迷茫的,我们在这里要正确理解SpringIoc容器,以后对我们学习会有很大的帮助的。其实它的容器是有一些类和接口来充当的,你可能又会很迷茫。这就是它与别的框架的不同之处,这一点也正在体现了它的无侵入性的一点,不像EJB需要专门的容器来运行,侵入性很大的重量级的框架。Spring只是一种轻量级的无侵入性的框架。说白了SpringIoc容器就是可以实例化BeanFactoryApplicationContext(扩展了BeanFactory)的类.
可能你对Ioc容器还是不太理解,慢慢来,刚刚接触的人都会很迷茫。我现在通过讲解一个例子来说明它的工作原理,你可能会恍然大悟,原来如此简单。
首先打开你的IDE编译器,我用的是Eclipse3.2+MyEclipse5.5.1
我举了一个大家比较熟悉的例子,用户登录验证。如果用户名为:admin 密码为:1234.
就会在控制台输出恭喜你,登录成功!反之输出“对不起,登录失败!”并在日志文件中记录登录信息。这里我用到的是log4j.(日志记录器)。我严格按分层思想和Spring中提倡的按接口编程的思想来演练这个简单的例子。可能你会想这么简单的为什么要那么麻烦呢?怎么不用一个类就解决了,做为程序员,我们时刻要记住,我们的代码要易维护,可重用,易扩展,低耦合,高内聚。如果你了解这些原则,你自然会明白这样麻烦的好处了。
我先整体的讲解一下工程中的目录结果:如下图
 
首先我们看一下UserLogin接口和它的实现部分UserLoginImpl
package com.chap2;
public interface UserLogin  {
   
    public boolean login(String userName,String passWord);
}
package com.chap2;
@SuppressWarnings("unused")
public class UserLoginImpl implements UserLogin {
    public boolean login(String userName,String passWord) {
       if (userName.equals("admin") && passWord.equals("1234"))
           return true;
       else
           return false;
    }
}
上面的接口只是简单的定义了一个方法,用于验证用户身份是否合法。在实现中只是简单的数据比较,实际当中应该从数据库中去取数据进行验证的,我们只要能说明问题就可以了。
然后在看一下业务逻辑层的UserService这里应该再对该类进行提取接口的,我只是写了一个类,如果你有兴趣的话,你可以在加上接口像上面的UserLogin一样,这样做是为了降低代码的耦合度,提高封装性。
package com.chap2.service;
import com.chap2.UserLogin;
public class UserService {
    private String userName;
    private String passWord;
    private UserLogin userLogin;
    public void setUserName(String userName) {
       this.userName = userName;
    }
    public void setPassWord(String passWord) {
       this.passWord = passWord;
    }
    public void setUserLogin(UserLogin userLogin) {
       this.userLogin = userLogin;
    }
    public String validateUser() {
       if (userLogin.login(userName, passWord))
           return "恭喜你,登录成功!";
       else
           return "对不起,登录失败!";
     }
}
在这个业务方法里其实是对userLogin中的方法的再次封装,这里面可能隐藏的用到了正面封装的模式(Facade)或叫做门面模式。它的好处是为了不让客户直接访问UserLogin中的方法,在实际的开发中UserLogin的方法应该放在DAO层中,这里的DAO是数据访问层的意思,其实就是对数据库执行的CRUD(增,删,改,查)操作。大家不要因为我多讲了一些就迷。我们应该养成好的编程习惯。也就是分工明细。层与层之间只能通过接口访问。至于上面提到的模式。你可以不先管了,只要你知道它里面用到了就可以了,以后我会把常用到的模式给你讲讲的。
这里的前台客户端的调用,我没用到html,jsp之类的页面,只是用了一个main()方法简单的模拟一下。同样可以起到上面讲的效果的。
public class Client {
    public static void main(String[] args) {
       // TODO 自动生成方法存根
       Log log = LogFactory.getLog(Client.class);
       //初始化,并加载配置文件。
       ApplicationContext context = new ClassPathXmlApplicationContext(
              "applicationContext.xml");
       BeanFactory beanFactory = (BeanFactory) context;
       //得到实例化的UserService
       UserService userService = (UserService) beanFactory
              .getBean("userService");
       //输出并记录登录信息
       log.info(userService.validateUser());
    }
}
先简单的看一下运行的结果是什么。
2007-11-21 11:04:44,765 INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - <Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@c51355: display name [org.springframework.context.support.ClassPathXmlApplicationContext@c51355]; startup date [Wed Nov 21 11:04:44 CST 2007]; root of context hierarchy>
2007-11-21 11:04:44,843 INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - <Loading XML bean definitions from class path resource [applicationContext.xml]>
2007-11-21 11:04:45,031 INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - <Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@c51355]: org.springframework.beans.factory.support.DefaultListableBeanFactory@1ce2dd4>
2007-11-21 11:04:45,046 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] - <Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1ce2dd4: defining beans [userLogin,userService]; root of factory hierarchy>
2007-11-21 11:04:45,078 INFO [com.chap2.util.Client] - <恭喜你,登录成功!>
你可能会想登录用户的信息在那?
所有的配置信息和实例化的工作都交给了SpringIoc容器,看看配置文件的配置。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans [url]http://www.springframework.org/schema/beans/spring-beans-2.0.xsd[/url]">
    <bean id="userLogin" class="com.chap2.UserLoginImpl" />
    <bean id="userService" class="com.chap2.service.UserService">
       <property name="userName">
           <value>admin</value>
       </property>
       <property name="passWord">
           <value>1234</value>
       </property>
       <property name="userLogin">
           <ref bean="userLogin" />
       </property>
    </bean>
</beans>
上面的配置文件只是描述了我们所用到类的调用关系,和数据的赋值<初始值>。我们在UserSerivce中要用到UserLogin中的方法,我们只需在这里简单的设置它的一个属性(property)就可以了,以前的编程要在代码中实现了,通过先new 一个UserLogin的实现对象,然后在调用其中的方法。我们这里只需在配置文件中简单的配置一下就可以了,在程序用到这个方法时,容器会自动先实例化UserLoginImpl,然后把它交给UserService使用。在UserService中不用担心实例化,以及管理它的生命周期了。全部让SpringIoc容器管理记行了。这样做减少了它们之间的依赖性,也就是降低它们的耦合度。
整个程序的工作流程是这样的。
main()方法中通过ApplicationContext来加载配置文件,然后把它转换为BeanFactory。这就是我们要讲的Spring中控制反转容器。它把所有的类都初始化,并放在这个容器中。在我们需要的时候只需像 UserService userService = (UserService) beanFactory.getBean("userService");通过配置文件中beanidname调用就可以了。不必在像以前的编程那样UserService userSerivce=new UserService();这样做还有一个好处就是让容器来管理它的生命周期,我们只需用就可以了,用完了在交给容器管理。而不用担心什么时候销毁它。
附加一些log4j的文件信息。就是工程目录下的log4j.properties.一定要放到src目录下,要不然程序运行时,它会找不到的。或直接把它放到class目录下。Log4j就是简单的记录一些日志信息,为以后使用的。下面是它的配置。其实还有多中形式的配置,可以是java属性文件形式的。像userLogin.log, userLogin.log.1就是一些备份文件。里面记录了程序运行时的一些信息。
log4j.rootLogger=INFO, stdout,logfile
 
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
 
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
log4j.appender.logfile.File=userLogin.log
log4j.appender.logfile.MaxFileSize=2KB
# Keep three backup files.
log4j.appender.logfile.MaxBackupIndex=3
# Pattern to output: date priority [category] - message
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
在这里我就不具体的讲了。在以后的章节中会讲到的。
  今天先写到这里.
分享到:
评论

相关推荐

    spring in action ch02

    通过学习《Spring in Action 第二章》,你将能够深入理解Spring框架的核心机制,并具备在项目中使用Spring进行IoC和DI的能力。这将为你后续学习Spring的其他高级特性和模块打下坚实基础,例如数据访问、Web开发、AOP...

    spring入门经典源码第二章

    2. **IoC容器**:Spring的核心是Inversion of Control(控制反转)容器,也称为依赖注入容器。IoC使得对象之间的依赖关系由容器管理,而不是由对象自身负责。这降低了组件之间的耦合度,提高了代码的可测试性和可...

    跟我学spring

    【第二章】IoC(控制反转)是Spring框架的核心概念之一,它涉及到对象创建的控制权从程序代码转移到外部容器。IoC有多种实现方式,包括依赖注入(DI)。在Spring中,IoC容器负责创建对象,初始化它们,并管理它们的...

    Beginning Spring(2015)

    第二章深入讲解了依赖注入(Dependency Injection, DI),这是Spring框架实现IoC的一种方式。依赖注入可以简化对象之间的依赖关系管理,并提高代码的灵活性和可维护性。Spring支持三种主要的依赖注入方式:构造器...

    Pro Spring 3

    - **第4章:引入IoC和DI**:详细介绍Spring中的IoC容器及依赖注入的概念和实现。 - **第5章:Spring配置详解**:深入探讨Spring配置的各种方式和技巧。 - **第6章:引入AOP**:讲解Spring AOP的基础概念、核心组件...

    领域驱动设计与模式实战

    在第十章中,作者探讨了如何博采其他设计技术,例如上下文为王的概念、服务导向架构(SOA)、控制反转(IoC)和依赖注入(DI)、面向方面编程(AOP)等。这些技术能够帮助开发者构建更为灵活和可维护的软件架构。 ...

    spring in action

    - **第2章:Bean的装配**:讲解如何使用Spring进行对象间的装配,包括依赖注入的基本概念和实践。 - **第3章:面向切面编程**:介绍面向切面编程的基础知识,以及如何在Spring中实现它。 - **第二部分:Spring在...

    springlive(共11章)

    - IoC(控制反转)与DI(依赖注入):讲解这两个核心概念,如何通过它们简化程序设计和管理对象间的依赖关系。 - AOP(面向切面编程):理解AOP的基本原理,以及如何在Spring中实现切面。 2. **第二章:搭建...

    Apress.Spring.Persistence – A.Running.Start.Feb.2009.pdf

    - **控制反转与依赖注入**:介绍了控制反转(IoC)和依赖注入(DI)的概念,以及它们如何促进代码解耦和模块化设计。 - **Spring设计模式与策略**:探讨了Spring框架内部所采用的设计模式,如工厂模式、单例模式等,...

    Apress.Spring.Recipes.A.Problem.Solution.Approach.2nd.Edition.Aug.2010

    依赖注入是Spring框架的核心特性之一,它通过反转控制(Inversion of Control, IoC)模式将对象之间的依赖关系交由框架管理,从而降低了对象之间的耦合度。面向切面编程则是一种编程范式,用于将横切关注点(Cross-...

    Java EE轻量级框架应用实战 课程教学大纲.docx

    - **关键词**:Spring框架、核心容器、依赖注入(DI)、控制反转(IoC)等。 - **目标要求**:理解Spring框架的核心思想,能够搭建基本的Spring应用程序。 7. **第7章 Spring框架中的Bean** - **内容概述**:...

    网络第一份struts2.0学习文档

    - 控制反转的概念:将对象创建和依赖注入的过程从代码中分离出来。 - Struts2如何支持IOC:通过配置文件指定依赖关系。 #### 八、Struts2标签 - **常用标签**: - `&lt;s:textfield&gt;`:显示文本框。 - `...

Global site tag (gtag.js) - Google Analytics