JavaWeb 之 Spring IoC 控制反转及整合 JUnit 单元测试

Spring IoC 控制反转 & 整合 JUnit 单元测试。


Spring 框架 IoC 功能之配置文件方式


Spring 框架中 <bean> 标签的配置

id 属性和 name 属性的区别

  • id————Bean 起个名字,在约束中采用 ID 的约束,唯一

    取值要求:必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号 id:不能出现特殊字符

  • name————Bean 起个名字,没有采用 ID 的约束(了解)

    取值要求:name 允许出现特殊字符,如果 <bean> 没有 id 的话,name 可以当做 id 使用
    Spring 框架在整合 Struts1 的框架的时候,Struts1 的框架的访问路径是以 / 开头的,例如:/bookAction

class 属性

Bean 对象的全路径:com.renkaigis.demo1.UserServiceImpl

scope 属性

scope 属性代表 Bean 的作用范围

singleton————单例(默认值)
prototype————多例,在 Spring 框架整合 Struts2 框架的时候,Action 类也需要交给 Spring 做管理,配置把 Action 类配置成多例!!
request————应用在 Web 项目中,每次 HTTP 请求都会创建一个新的 Bean
session————应用在 Web 项目中,同一个 HTTP Session 共享一个 Bean
globalsession————应用在 Web 项目中,多服务器间的 session

Bean 对象的创建和销毁的两个属性配置(了解)

Spring 初始化 bean 或销毁 bean 时,有时需要作一些处理工作,因此 spring 可以在创建和销毁 bean 的时候调用 bean 的两个生命周期方法

  • init-method————当 bean 被载入到容器的时候调用 init-method 属性指定的方法

  • destroy-method————当bean从容器中删除的时候调用 destroy-method 属性指定的方法

想查看 destroy-method 的效果,有如下条件

scope = "singleton"有效
② web 容器中会自动调用,但是 main 函数或测试用例需要手动调用(需要使用 ClassPathXmlApplicationContextclose() 方法)

依赖注入(DI)

IoCDI 的概念

  • IoC————Inverse of Control,控制反转,将对象的创建权反转给 Spring!!
  • DI————Dependency Injection,依赖注入,在 Spring 框架负责创建 Bean 对象时,动态的将依赖对象注入到 Bean 组件中!!

DI(依赖注入)

  • 例如:如果 UserServiceImpl 的实现类中有一个属性,那么使用 Spring 框架的 IoC 功能时,可以通过依赖注入把该属性的值传入进来!!
  • 具体的配置如下:
1
2
3
<bean id="userService" class="com.renkaigis.demo1.UserServiceImpl">
<property name="name" value="小风"/>
</bean>

Spring 框架的属性注入

对于类成员变量,常用的注入方式有两种

  • 构造函数注入
  • 属性 setter 方法注入

构造方法的注入方式

  • 编写 Java 类,提供构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Car1 {
private String cname;
private Double price;

public Car1(String cname, Double price) {
this.cname = cname;
this.price = price;
}

@Override
public String toString() {
return "Car1{" + "cname='" + cname + '\'' + ", price=" + price + '}';
}
}
  • 编写配置文件
1
2
3
4
5
<!--演示构造方法注入的方式-->
<bean id="car1" class="com.renkaigis.demo2.Car1">
<constructor-arg name="cname" value="奇瑞QQ"/>
<constructor-arg name="price" value="25000"/>
</bean>
  • 测试:
1
2
3
4
5
6
@Test
public void run1() {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Car1 c1 = (Car1) ac.getBean("car1");
System.out.println(c1);
}

setter 方法的注入方式

  • 编写 Java 的类,提供属性和对应的 set 方法即可

  • 编写配置文件

  • 如果 Java 类的属性是另一个 Java 的类,那么需要怎么来注入值呢?

    <property name="name" rel="具体的Bean的ID或者name的值"/>

  • 例如:

1
2
3
4
<bean id="person" class="com.renkaigis.demo2.Person">
<property name="pname" value="美美"/>
<property name="car2" ref="car2"/>
</bean>

Spring 2.5 版本:p 名称空间的注入(了解)

先引入 p 名称空间

  • schema 的名称空间中加入该行:xmlns:p="http://www.springframework.org/schema/p"

使用 p 名称空间的语法

  • p:属性名 = “”
  • p:属性名-ref = “”

测试

1
2
<!--采用 p 名称空间注入的方式-->
<bean id="car1" class="com.renkaigis.demo2.Car1" p:cname="保时捷" p:price="1000000"/>

Spring 3.0 版本:SpEL注入方式(了解)

SpEL:Spring Expression Language 是 Spring 的表达式语言,有一些自己的语法。

  • 语法
1
#{SpEL}
1
2
3
4
5
<!-- SpEL的方式 -->
<bean id="person" class="com.renkaigis.demo4.Person">
<property name="pname" value="#{'小风'}"/>
<property name="car2" value="#{car2}"/>
</bean>

数组,集合(List,Set,Map),Properties 等的注入

数组和 List 集合

如果是数组或者List集合,注入配置文件的方式是一样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 演示集合注入的方式
*/
public class User {
// 数组
private String[] arrs;
// 集合
private List<String> list;

public void setList(List<String> list) {
this.list = list;
}

public void setArrs(String[] arrs) {
this.arrs = arrs;
}

@Override
public String toString() {
return "User{" + "arrs=" + Arrays.toString(arrs) + ", list=" + list + '}';
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<bean id="user" class="com.renkaigis.demo3.User">
<!--注入数组-->
<property name="arrs">
<list>
<value>哈哈</value>
<value>呵呵</value>
<value>嘿嘿</value>
</list>
</property>
<!--注入集合-->
<property name="list">
<list>
<value>天哪</value>
<value>god</value>
</list>
</property>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 测试注入数组
*/
@Test
public void run1() {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) ac.getBean("user");
System.out.println(user);
}

/**
* 测试注入集合
*/
@Test
public void run2() {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) ac.getBean("user");
System.out.println(user);
}

Set 集合

如果是 Set 集合,注入的配置文件方式如下:

1
2
3
4
5
6
7
<!--注入 set 集合-->
<property name="sets">
<set>
<value>哈哈</value>
<value>呵呵</value>
</set>
</property>

Map 集合

如果是 Map 集合,注入的配置方式如下:

1
2
3
4
5
6
7
<!--注入 map-->
<property name="map">
<map>
<entry key="aaa" value="小瓜"/>
<entry key="bbb" value="小宗"/>
</map>
</property>

properties 属性文件

如果是 properties 属性文件的方式,注入的配置如下:

1
2
3
4
5
6
7
<!--注入属性文件-->
<property name="pro">
<props>
<prop key="username">root</prop>
<prop key="password">1234</prop>
</props>
</property>

Spring 配置文件分开管理(了解)

例如:在 src 的目录下又多创建了一个配置文件,现在是两个核心的配置文件,那么加载这两个配置文件的方式有两种!

  • 主配置文件中引入其他的配置文件:
1
2
<!-- 推荐使用 -->
<import resource="applicationContext2.xml"/>
  • 工厂创建的时候直接加载多个配置文件:
1
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext2.xml");

Spring 框架 IoC 功能之注解方式


Spring框架 IoC 之注解方式快速入门

步骤一:导入注解开发所有需要的 jar 包

  • 引入IoC容器必须的6个jar包

    spring-beans-4.2.4.RELEASE.jar
    spring-context-4.2.4.RELEASE.jar
    spring-core-4.2.4.RELEASE.jar
    spring-expression-4.2.4.RELEASE.jar
    com.springsource.org.apache.commons.logging-1.1.1.jar
    com.springsource.org.apache.log4j-1.2.15.jar

  • 多引入一个:Spring框架的AOP的jar包,spring-aop的jar包

步骤二:创建对应的包结构,编写 Java 的类

  • UserService————接口
  • UserServiceImpl————具体的实现类

步骤三:引入约束

在 src 的目录下,创建 applicationContext.xml 的配置文件,然后引入约束。注意:因为现在想使用注解的方式,那么引入的约束发生了变化。

  • 需要引入context的约束,具体的约束如下:
1
2
3
4
5
6
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>

步骤四:在 applicationContext.xml 配置文件中开启组件扫描

  • Spring的注解开发:组件扫描
1
2
<!--开启注解的扫描-->
<context:component-scan base-package="com.renkaigis.demo1"/>
  • 注意:可以采用如下配置:
1
2
<!-- 这样是扫描com.renkaigis包下所有的内容 -->
<context:component-scan base-package="com.renkaigis"/>

步骤五:在 UserServiceImpl 的实现类上添加注解

  • @Component(value=”userService”) – 相当于在XML的配置方式中
1
2
3
4
5
6
7
8
9
10
11
12
/**
* @Component(value = "userService")
* 等价于
* <bean id="userService" class="com.renkaigis.demo1.UserServiceImpl"/>
*/
@Component(value = "userService")
public class UserServiceImpl implements UserService {
@Override
public void sayHello() {
System.out.println("Hello Spring!");
}
}

步骤六:编写测试代码

1
2
3
4
5
6
@Test
public void run1() {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService us = (UserService) ac.getBean("userService");
us.sayHello();
}

Spring 框架中 Bean 管理的常用注解

类注解

  • @Component:组件。(作用在类上)

  • Spring 中提供 @Component 的三个衍生注解:(功能目前来讲是一致的)

    @Controller————作用在WEB层
    @Service————作用在业务层
    @Repository————作用在持久层

  • 说明:这三个注解是为了让标注类本身的用途清晰,Spring在后续版本会对其增强

属性注解

属性注入的注解(说明:使用注解注入的方式,可以不用提供 set 方法)

  • 如果是注入的普通类型,可以使用 value 注解

    @Value————用于注入普通类型

1
2
3
4
5
6
7
8
9
10
@Component(value = "userService")
public class UserServiceImpl implements UserService {
@Value(value = "小美")
private String name;

@Override
public void sayHello() {
System.out.println("Hello Spring!" + name);
}
}
  • 如果注入的是对象类型,使用如下注解

    @Autowired————默认按类型进行自动装配,寻找实现类。缺点:实现类多的话就出错了

  • 如果想按名称注入

    @Qualifier————强制使用名称注入

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component(value = "userService")
public class UserServiceImpl implements UserService {
// 按类型自动装配
@Autowired
@Qualifier(value = "ud") // 按名称注入
private UserDao userDao;

@Override
public void sayHello() {
System.out.println("Hello Spring!");
userDao.save();
}
}
  • @Resource————相当于 @Autowired@Qualifier 一起使用

    强调:@Resource 是 Java 提供的注解
    属性使用 name属性

1
2
@Resource(name = "ud")
private UserDao userDao;

Bean 的作用范围和生命周期的注解

Bean 的作用范围注解

  • 注解为 @Scope(value = "prototype"),作用在上。值如下:

    singleton————单例,默认值
    prototype————多例

Bean 的生命周期的配置(了解)

  • 注解如下:

    @PostConstruct————相当于 init-method
    @PreDestroy————相当于 destroy-method


Spring 框架整合 JUnit 单元测试


为了简化了 JUnit 的测试,使用 Spring 框架也可以整合测试。

具体步骤

要求:必须先有 JUnit 的环境(即已经导入了 JUnit4 的开发环境)!!

  • 步骤一:在程序中引入:spring-test.jar

  • 步骤二:在具体的测试类上添加注解

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(“classpath:applicationContext.xml”)

以后不用再自己 new 工厂了,配置文件会自动加载:

1
2
3
4
5
6
7
8
9
10
11
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class demo2 {
@Resource(name = "userService")
private UserService userService;

@Test
public void run1() {
userService.sayHello();
}
}