一个尴尬的年纪,没有儿时的勇气,年少的冲动,成熟的物质,消融了那些不切实际的臆想,也接受了很多难以为继的事实,一直在路上 。

Spring 实现 IoC

理解 “ 控制反转(IoC)
 
  控制反转(IoC):用白话来讲,就是由 Spring 容器控制程序中类与类之间的关系,而非传统实现中,由程序代码直接操控。这也就是所谓 “控制反转” 的概念所在:控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。
  控制反转(Inversion of Control,IoC),也称为依赖注入( Dependency Injection,DI),是面向对象编程中的一种设计理念,用来降低程序代码之间的耦合度。
 
  IoC 理解:传统模式中是类和类之间直接调用,所以有很强的耦合度,程序之间的依赖关系比较强,后期维护时牵扯的比较多。  IoC:用配置文件(XML)来描述类与类之间的关系,由容器来管理,降低了程序间的耦合度,程序的修改可以通过简单的配置文件修改来实现。 
 
   依赖:在代码中一般指通过局部变量、方法参数、返回值等建立的对于其他对象的调用关系。例如,在 A 类的方法中,实例化了 B 类的对象并调用其方法以完成特定的功能,我们就说 A 类依赖于 B 类。
 
    说明
       1、类与类之间的高度耦合将使程序不具备优良的可扩展性和可维护性。如常见的业务层调用数据访问层实现持久化操作, UserServiceImpl 类与 UserDaoImpl 类存在依赖关系(即高度耦合),如果因为需求变化需要替换 UserDao 的实现类,将导致 UserServiceImpl 中的代码随之发生修改,不利于扩展和维护。
      2、几乎所有的应用都是由两个或更多的类通过彼此合作来实现完整的功能,类与类之间的依赖关系增加了程序开发的复杂程度,我们在开发一个类的时候,还要考虑对正在使用该类的其他类的影响。
 
 
Spring 实现 IoC
  我们对 “控制反转” 有了了解,那么在项目中如何使用 Spring 实现 “控制反转” 呢?案例:开发第一个 Spring 项目 HelloSpring,输出 “Hello Spring!” 。
    案例要求:编写 HelloSpring 类输出 “Hello,Spring!”,其中字符串内容 “Spring” 通过 Spring 框架赋值到 HelloSpring 类中。
    实现思路:
        (1)下载 Spring 并添加到项目中。
        (2)编写 HelloSpring 类。
        (3)编写 Spring 配置文件。
        (4)编写代码通过 Spring 获取 HelloSpring 实例。
 
  (1)在 eclipse 中新建一个项目 HelloSpring,将所需的 Spring 的 jar 文件添加到项目中。需要注意的是,Spring 的运行依赖于 commons-logging 组件,需要将相关 jar 文件一并导入。为了方便观察 Bean 实例化过程,我们采用 log4j 作为日志输出,所以也应该将 log4j 的 jar 文件添加到项目中。
 
HelloSpring 需要的 jar 文件

   

  (2)为该项目添加 log4j.properties 文件,用来控制日志输出。log4j.properties 文件内容如下:

# rootLogger是所有日志的根日志,修改该日志属性将对所有日志起作用
# 下面的属性配置中,所有日志的输出级别是info,输出源是con
log4j.rootLogger=info,con
# 定义输出源的输出位置是控制台
log4j.appender.con=org.apache.log4j.ConsoleAppender
# 定义输出日志的布局采用的类
log4j.appender.con.layout=org.apache.log4j.PatternLayout
# 定义日志输出布局
log4j.appender.con.layout.ConversionPattern=%d{MM-dd HH:mm:ss}[%p]%c%n -%m%n

 

  (3)编写 HelloSpring 类,代码如下:
package cn.springdemo;

/**
 * 第一个Spring,输出"Hello,Spring!"。
 */
public class HelloSpring {
    // 定义who属性,该属性的值将通过Spring框架进行设置
    private String who = null;

    /**
     * 定义打印方法,输出一句完整的问候。
     */
    public void print() {
        System.out.println("Hello," + this.getWho() + "!");
    }

    /**
     * 获得 who。
     * 
     * @return who
     */
    public String getWho() {
        return who;
    }

    /**
     * 设置 who。
     * 
     * @param who
     */
    public void setWho(String who) {
        this.who = who;
    }
    
}

   

  (4)编写 Spring 配置文件,在项目的 classpath 根路径下创建 applicationContext.xml 文件(为便于管理框架的配置文件,可在项目中创建专门的 Source folder 源文件夹,如 resources 目录,并将 Spring 配置文件创建在其根路径下)。在 Spring 配置文件中创建 HelloSpring 类的实例并为 who 属性注入属性值。

<?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
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    
    <!-- 通过bean元素声明需要Spring创建的实例。该实例的类型通过class属性指定,并通过id属性为该实例指定一个名称,以便在程序中使用 -->
    <bean id="helloSpring" class="cn.springdemo.HelloSpring">
        <!-- property元素用来为实例的属性赋值,此处实际是调用setWho()方法实现赋值操作 -->
        <property name="who">
            <!-- 此处将字符串"Spring"赋值给who属性 -->
            <value>Spring</value>
        </property>
    </bean>
    
</beans>

  说明:

     1、在 Spring 配置文件中,使用 <bean> 元素来定义 Bean(也可称为组件)的实例。这个元素有两个常用属性:一个是 id,表示定义的 Bean 实例的名称,另一个是 class,表示定义的 Bean 实例的类型。

     2、使用 <bean> 元素定义一个组件时,通常需要使用 id 属性为其指定一个用来访问的一的名称。如果想为 Bean 指定更多的别名,可以通过 name 属性指定,名称之间使用逗号、分号或空格进行分隔。

     3、在本例中,Spring 为 Bean 的属性赋值是通过调用属性的 setter 方法实现的,这种做法称为 “设值注入”,而非直接为属性赋值。若属性名为 who,但是 setter 方法名为 setSomebody(),Spring 配置文件中应写成 name="somebody" 而非name="who"。所以在为属性和 setter 访问器命名时,一定要注意遵循 JavaBean 的命名规范。

 

  (5)使用 Junit 进行单元测试

package test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.springdemo.HelloSpring;

public class HelloSpringTest {

    @Test
    public void helloSpring() {
        // 通过ClassPathXmlApplicationContext实例化Spring的上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过ApplicationContext的getBean()方法,根据id来获取bean的实例
        HelloSpring helloSpring = (HelloSpring) context.getBean("helloSpring");
        // 执行print()方法
        helloSpring.print();
    }

}

   说明:

     1、通过 “Hello,Spring!" 的例子,我们发现 Spring 会自动接管配置文件中 Bean 的创建和为属性赋值的工作。 Spring 在创建 Bean 的实例后,会调用相应的 setter 方法为实例设置属性值。实例的属性值将不再由程序中的代码来主动创建和管理,改为被动接受 Spring 的注入,使得组件之间以配置文件而不是硬编码的方式组织在一起。

     2、相对于 “控制反转” ,“依赖注入” 的说法也许更容易理解一些,即由容器(如 Spring)负责把组件所 “依赖” 的具体对象 “注入” (赋值) 给组件,从而避免组件之间以硬编码的方式耦合在一起。

     3、ApplicationContext 是一个接口,负责读取 Spring 配置文件,管理对象的加载、生成,维护 Bean 对象与 Bean 对象之间的依赖关系,负责 Bean 的生命周期等。ClassPathXmlApplicationContext 是 ApplicationContext 接口的实现类,用于从 classpath 路径中读取 Spring 配置文件。

     4、除了 ClassPathXmlApplicationContext,ApplicationContext 接口还有其他实现类。例如,FileSystemXmlApplicationContext 也可以用于加载 Spring 配置文件。

     5、除了 ApplicationContext  及其实现类,还可以通过 BeanFactory 接口及其实现类对 Bean 组件实施管理。事实上,ApplicationContext 就是建立在 BeanFactory 的基础之上,BeanFactory 是 Spring IoC 容器的核心,负责管理组件和它们之间的依赖关系,应用程序通过 BeanFactory 接口与 Spring IoC 容器交互。 ApplicationContext 是 BeanFactory 的子接口,可以对企业级开发提供更全面的支持。

 
 
简单总结
        <bean> 元素的作用:定义 Bean 的实例。(即创建类的对象)  
     <bean> 的 id 属性:定义的 Bean 实例的名称(即定义对象的名称)
     <bean> 的 class 属性:定义的 Bean 实例的类型(即指定创建的对象属于哪个类,要写完全限定名)
     <bean> 的 <property> 子元素作用:为类中指定属性赋值。
          <property> 的 name 属性:指定属性的名称
          <property> 的 <value> 子元素作用:为指定的属性赋值
 
知识拓展
   一、深入理解 Java 中字段与属性的区别
    Java 中的属性(property),通常可以理解为 get 和 set 方法。而
 
     1.1 字段(filed)
    字段(field),通常叫做“类成员”,或 "类成员变量”,有时也叫“域”,理解为“数据成员”,用来承载数据的。类成员(字段),通常是在类中定义的类成员变量,例如下面的代码:我们可以说 Person 类中有一个成员变量叫做 name,Person 类有一个字段 name。

    字段一般用来承载数据,所以为了安全性,一般定义为私有的。字段和常量描述了类的数据(域),当这些数据的某些部分不允许外界访问时,根据 “对象封装” 的原则,应尽量避免将一个类型的字段以公有方式提供给外部。除了 final 修饰的常量。一般将其设置为 private 类型。既然是私有,那外界怎么访问呢? 当然是通过 Java 的属性方法。

 
    1.2 属性(property)
    属性只局限于类中方法的声明,并不与类中其他成员相关,属于 JavaBean 的范畴。当一个类中拥有getXxx()和setXxx()这样一对方法时,我们可以说,这个类中拥有一个可读写的 xxx 属性。如果去掉了 set 的方法,则是可读属性,反之亦然。
    属性的定义规则是:setter/getter 方法名,去掉 set/get 后,将剩余部分首字母小写得到的字符串就是这个类的属性。
     可以创建属性,将字段和属性封装在一起。通过属性可以像访问字段一样访问数据成员,实现数据的封装,避免使用非法数据赋值,保证数据完整性,同时类内部发生修改时,避免整个程序的修改。但是字段和属性是完全不同的两个概念。
public class Person {
    private String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

 

   二、什么是 JavaBean?
  JavaBean 是一个遵循特定写法的 Java 类,指的是一种特殊的 Java 类,它通常用来实现一些比较常用的简单功能,并可以很容易的被重用或者是插入其他应用程序中去。是一种 Java 语言编写的可重用组件,JavaBean 遵循 “一定编程原则” 。规则如下:
        1、这个类必须具有一个公共的(public)无参构造函数;
        2、所有属性私有化(private);
        3、私有化的属性必须通过 public 类型的方法(getter和setter)暴露给其他程序,并且方法的命名也必须遵循一定的命名规范。 
        4、这个类应是可序列化的。(比如可以实现Serializable 接口,用于实现bean的持久性)
 
  JavaBean 的一些理解:
     1、JavaBean 在 Java EE 开发中,通常用于封装数据,对于遵循以上写法的 JavaBean 组件,其它程序可以通过反射技术实例化 JavaBean 对象(内省机制),并且通过反射那些遵循命名规范的方法,从而获知 JavaBean 的属性,进而调用其属性保存数据。
     2、因为这些要求主要是靠约定而不是靠实现接口,所以许多开发者把 JavaBean 看作遵从特定命名约定的 POJO。(可以这么理解,POJO按JavaBean的规则来,就可以变成JavaBean)。 简而言之,当一个POJO可序列化,有一个无参的构造函数,使用getter和setter方法来访问属性时,他就是一个JavaBean。
     3、JavaBean是一种组件技术,就好像你做了一个扳手,而这个扳手会在很多地方被拿去用,这个扳子也提供多种功能(你可以拿这个扳手扳、锤、撬等等),而这个扳手就是一个组件。

     4、对于JavaBean,就是一个Java模型组件,他为使用Java类提供了一种标准的格式,在用户程序和可视化管理工具中可以自动获得这种具有标准格式的类的信息,并能够创建和管理这些类。 
     5、JavaBean可以使应用程序更加面向对象,可以把数据封装起来,把应用的业务逻辑和显示逻辑分离开,降低了开发的复杂程度和维护成本!
     6、JavaBean 是一种JAVA语言写成的可重用组件。为写成JavaBean,类必须是具体的和公共的,并且具有无参数的构造器。JavaBeans 通过提供符合一致性设计模式的公共方法将内部域暴露称为属性。众所周知,属性名称符合这种模式,其他Java 类可以通过内省机制发现和操作这些JavaBean 属性。

   三、Java 项目中 classpath 路径讲解
  1、src 不是 classpath,WEB-INF/classes、lib 才是 classpath,WEB-INF/ 是资源目录,客户端不能直接访问。WEB-INF/classes 目录存放 src 目录 Java 文件编译之后的 class文件,xml、properties 等资源配置文件,这是一个定位资源的入口。
  2、lib 和 classes 同属 classpath,两者的访问优先级为: lib>classes。
  3、引用 classpath 路径下的文件,只需在文件名前加 classpath:
 
 
posted @ 2018-10-22 19:41  斯文败类i  阅读(349)  评论(0编辑  收藏  举报