1. Junit 测试工具
Junit 是一个 Java 编程语言的单元测试框架
常见的注解有:
- @BeforeClass :表示使用此注解的方法在测试类被调用之前执行,在一个测试类中只能声明此注解一次,此注解对应的方法只能被执行一次。
- @AfterClass :表示使用此注解的方法在测试类被调用结束退出之前执行,在一个测试类中只能声明此注解一次,并且此注解对应的方法只能被执行一次。
- @Before:表示使用此注解的方法在每个@Test调用之前被执行,即一个类中有多少个@Test注解方法,那么@Before注解的方法就会被调用多少次。
- @After:表示使用此注解的方法在每个@Test调用结束之后被执行,即一个类中有多少个@Test注解方法,那么@Before注解的方法就会被调用多少次。
- @Test :表示使用此注解的方法为一个单元测试用例,在一个测试勒种可以多次声明此注解,每个注解为@Test的方法只被执行一次
Junit测试用例的完整的执行顺序:
- @BeforeClass–>@Before–>@Test–>@After—>@AfterClass
测试验证:
-
需要创建的类有如下红框标记:
-
先编写一个实体类Student
package com.zz.domain;
public class Student {
private int id; //学号
private String name; //姓名
private String gender; //性别
private String birthday; //出生日期
private String major; //专业
public Student() {
}
public Student(int id, String name, String gender, String birthday, String major) {
this.id = id;
this.name = name;
this.gender = gender;
this.birthday = birthday;
this.major = major;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", birthday='" + birthday + '\'' +
", major='" + major + '\'' +
'}';
}
}
- 再编写applicationContext.xml文档
<?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.xsd">
<bean id="s1" class="com.zz.domain.Student">
<property name="id" value="001"/>
<property name="name" value="张一"/>
<property name="gender" value="男" />
<property name="birthday" value="2009-05-18"/>
<property name="major" value="九阴真经" />
</bean>
<bean id="s2" class="com.zz.domain.Student">
<property name="id" value="002"/>
<property name="name" value="黄二"/>
<property name="gender" value="男" />
<property name="birthday" value="2011-07-08"/>
<property name="major" value="如来神掌" />
</bean>
</beans>
- 编写测试类StudentDomainTest
package com.zz.domain;
import org.junit.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StudentDomainTest {
private static ApplicationContext context;
//@BeforeClass,测试类的初始化过程,仅仅初始化一次。
@BeforeClass
public static void initContext(){
System.out.println("执行了@BeforeClass的initContext()...");
context = new ClassPathXmlApplicationContext("applicationContext.xml");
}
//用来初始化测试用例的,每次测试都执行。
@Before
public void initTest(){
System.out.println("执行了@Before的initTeset()...");
}
@After
public void afterTest(){
System.out.println("执行了@After的afterTeset()...");
}
//测试用例
@Test
public void testGetStudents1(){
//初始化上下文(IOC容器)
//ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("执行了@Test的testGetStudents1()...");
Student s1 = (Student) context.getBean("s1");
System.out.println(s1);
}
//测试用例
@Test
public void testGetStudents2(){
//初始化上下文(IOC容器)
//ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("执行了@Test的testGetStudents2()...");
Student s2 = (Student) context.getBean("s2");
System.out.println(s2);
}
@AfterClass
public static void destroy(){
System.out.println("执行了@AfterClass的destroy()...");
}
}
- 运行结果
2. getBean的五种用法
(1)getBean(String id/name)
id不能重复,只能写一个,并且不能和name重复
name可写多个,并且也不能和id重复
<bean id="s1" class="com.zz.domain.Student">
<bean name="name1,name2,name3" class="com.zz.domain.Student">
需要进行类型转换
Student s1 = (Student) context.getBean("s1");
(2)getBean(Class clazz)
通过类型加载,要求类型不能重复。好处是:无需类型转换
Student s1 = context.getBean(Student.class);
(3)getBean(String id/name,Class clazz);
通过id/name和类型查找,好处是:无需类型转换。
Student s1 = context.getBean("s1", Student.class);
(4)getBean(Class clazz,Object …objs)
Student s1 = context.getBean(Student.class,new Object[]{003,"胡三","女","1999-11-10","降龙十八掌"});
如果第二个参数是带对象数组的,一定是想返回使用对象数组初始化属性的对象。运行结果发现还是之前的对象。
解决方法:通过工厂模式生成对象
工厂类 StudentFactory
package com.zz.factory;
import com.zz.domain.Student;
import java.lang.reflect.Constructor;
//使用工厂模式来生成学生。
public class StudentFactory {
public static Student getStudentInstance(int sid,String sname,String gender,String birthday,String major) throws Exception{
Class clazz = Class.forName("com.zz.domain.Student");
//反射出构造方法。
Constructor constructor = clazz.getConstructor(int.class,String.class,String.class,String.class,String.class);
return (Student)constructor.newInstance(sid,sname,gender,birthday,major);
}
}
applicationContext.xml文档
<!--prototype 原型(非单例)-->
<bean id="s1" factory-method="getStudentInstance" class="com.zz.factory.StudentFactory" scope="prototype">
<constructor-arg name="id" value="111"/>
<constructor-arg name="name" value=""/>
<constructor-arg name="gender" value=""/>
<constructor-arg name="birthday" value=""/>
<constructor-arg name="major" value=""/>
</bean>
运行结果
(5)getBean(String id/name,Object …objs)
与(4)方法相同,通过工厂方法生成对象,objs 初始化对象时的参数列表
3. 属性的注入方式
在实际项目开发时一般不配置applicationContext.xml,太麻烦,都是使用注解来注入
在applicationContext.xml中只需要开启注解:
<context:component-scan base-package="com.zz"/>
xml配置:简单来说就是配置applicationContext.xml. 里面通过注入对象。
注解配置:类上面添加@Configuration注解,那么这个类作用等同于applicationContext.xml
@Bean 注解的作用等同于
(1)通过property注入
applicationContext.xml文档
<bean id="s2" class="com.zz.domain.Student">
<property name="id" value="002"/>
<property name="name" value="黄二"/>
<property name="gender" value="男" />
<property name="birthday" value="2011-07-08"/>
<property name="major" value="如来神掌" />
</bean>
</beans>
测试类
@Test
public void testPropertiesInject(){
//1.通过property注入
Student s1 = (Student) context.getBean("s2");
System.out.println(s1); //Student{id=2, name='黄二', gender='男', birthday='2011-07-08', major='如来神掌'}
}
(2)通过 constructor-arg 注入,本质是调用构造方法
applicationContext.xml文档
<!--构造方法注入-->
<bean name="hehe,haha" class="com.zz.domain.Student">
<constructor-arg name="id" value="111"/>
<constructor-arg name="name" value="郭三"/>
<constructor-arg name="gender" value="男"/>
<constructor-arg name="birthday" value="1999-09-10"/>
<constructor-arg name="major" value="九阴真经"/>
</bean>
测试类
@Test
public void testPropertiesInject(){
//通过构造方法注入
Student s1 = (Student) context.getBean("haha");
System.out.println(s1); //Student{id=111, name='郭三', gender='男', birthday='1999-09-10', major='九阴真经'}
}
(3)通过@Value 注解注入,不推荐这种
开启注解方法:在applicationContext.xml 中添加
<context:component-scan base-package=“com.zz”/>
<!--@Value注解注入-->
<!--开启注解功能-->
<context:component-scan base-package="com.zz"/>
<bean name="hehe,haha" class="com.zz.domain.Student" scope="prototype">
</bean>
Student类
在成员变量前都加@value(“xxx”),这样做会造成初始化任何一个Students对象,属性赋值都是一样的,所以不推荐使用。
@Value("777")
private int id; //学号
@Value("周六")
private String name; //姓名
@Value("男")
private String gender; //性别
@Value("1998-02-03")
private String birthday; //出生日期
@Value("吹牛逼")
private String major; //专业
测试类
@Test
public void testPropertiesInject(){
//通过 @Value注入
Student s1 = (Student) context.getBean("haha");
System.out.println(s1); //Student{id=777, name='周六', gender='男', birthday='1998-02-03', major='吹牛逼'}
}
(4)通过@Bean 注入,配合@Configuration 使用
创建一个SpringConfiguration类
package com.zz.config;
import com.zz.domain.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//带@Configuration注解的类等同于applicationContext.xml
@Configuration
public class SpringConfiguration {
//在IOC容器中初始化了一个id=haha的对象
@Bean("haha")
public Student getStudentsBean1(){
Student s = new Student(666,"郭九","男","2009-10-10","画画");
return s;
}
@Bean("xixi")
public Student getStudentsBean2(){
Student s = new Student(200,"陈三","女","2000-10-10","美术");
return s;
}
}
同样applicationContext.xml中只需要开启注解:
添加 <context:component-scan base-package=“com.zz”/>
测试类
@Test
public void testPropertiesInject(){
//通过 注解注入
Student s1 = (Student) context.getBean("xixi");
//改为haha,得到的就是Student{id=666, name='郭九', gender='男', birthday='2009-10-10', major='画画'}
System.out.println(s1); //Student{id=200, name='陈三', gender='女', birthday='2000-10-10', major='美术'}
}
4. bean的生存范围和加载策略
生存范围:
-
scope有两个常用属性:singleton(单例)和prototype(原型)。默认情况下为singleton。
-
singleton:无论这个bean被取多少次,都是同一个对象
<bean id="001" class="com.zz.domain.Student">
-
prototype:每次bean取的对象不同
<bean id="001" class="com.zz.domain.Student" scope="prototype">
-
对应的注解的写法:
@Scope("singleton") 或 @Scope("prototype")
加载策略:
在实体类上添加
@Component
@Lazy(true/false)
@Lazy(true) 表示懒加载,用到的时候再调用构造方法来实例化bean,不用就不实例化
@Lazy(false) 表示积极加载,默认是false; 不管是否用到,都事先加载出来
5. 自定义属性的注入方式
如实体类People中带有复杂属性Car
创建两个实体类People和Car
package com.zz.domain;
public class Person {
private String name;
private String gender;
private int age;
private Car car;
public Person() {
}
public Person(String name, String gender, int age, Car car) {
this.name = name;
this.gender = gender;
this.age = age;
this.car = car;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
", car=" + car +
'}';
}
}
package com.zz.domain;
public class Car {
private String brand;
private String color;
private int price;
public Car() {
}
public Car(String brand, String color, int price) {
this.brand = brand;
this.color = color;
this.price = price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", color='" + color + '\'' +
", price=" + price +
'}';
}
}
创建一个注解配置类 SpringConfiguration2
package com.zz.config;
import com.zz.domain.Car;
import com.zz.domain.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfiguration2 {
@Bean("p1")
public Person getPerson1(@Autowired Car car){
//按类型注入一个Car
return new Person("张三","男",30,car);
}
@Bean("car1")
public Car getCar1(){
return new Car("BMW","黑色",400000);
}
}
创建 PersonDomainTest 测试类
package com.zz.domain;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class PersonDomainTest {
private static ApplicationContext context;
//@BeforeClass,测试类的初始化过程,仅仅初始化一次。
@BeforeClass
public static void initContext(){
System.out.println("执行了initContext..");
context = new ClassPathXmlApplicationContext("applicationContext.xml");
}
@Test
public void testGetPersonBean(){
Person p = (Person) context.getBean("p1");
System.out.println(p); //Person{name='张三', gender='男', age=30, car=Car{brand='BMW', color='黑色', price=400000}}
}
}
6. Spring中各类注解的作用
@Component:添加在实体类,表示是一个组件
@Repository:添加在接口上,表示是接口
@Controller:添加在控制层上,表示是一个Controller,Controller属于SpringMVC的内容
@Service:添加在服务层上,表示是服务层代码
@Autowire:自动注入,根据类型
@Resource:自动注入,根据名字
@Bean:表示一个bean对象
@Configuration:配置注解
@Scope:生存范围
@Lazy:加载策略