1. Spring测试:
我们测试Spring需要手动读取配置文件,getBean,但是Spring也为我们提供了自动化的测试方法。
1)引入spring-test依赖,注意这个测试的包需要与我们引入的spring框架的包版本一致,并且不同的版本所支持的最低junit版本也不一致,本人使用的是5.2.6,最低需要junit 4.12的支持。
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--引入web会将所有的spring相关依赖全部导入-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!--引入Spring测试环境-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
</dependencies>
2)使用注解替代和自动装配替代手动读取配置文件和装配bean
2. jdbcTemplate:Spring提供的一款操作数据库的模板(感受IoC)。
1)引入依赖(使用Druid连接池)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
2)现在我们使用Spring管理,所以需要用的类得先注入Spring容器才行,并为jdbcTemplate配置使用的连接池
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="root"/>
<property name="password" value="zjm@?42393"/>
<property name="url" value="jdbc:mysql://localhost:3306/study_mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
这边注意一下,在xml文件中,使用字符&需要转义成&。
3)测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:beans.xml")
public class TestFirst {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
public void testCreateBean(){
jdbcTemplate.execute("select * from t_user");
}
}
当然了,后续的开发我们还是以使用Mybatis为主流,这边的演示时为了展示Spring集成开发环境。
我们再试试用java配置类配置:
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
@Configuration
public class jdbcConfig {
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("root");
dataSource.setPassword("zjm@?42393");
dataSource.setUrl("jdbc:mysql://localhost:3306/study_mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
return new JdbcTemplate(dataSource);
}
}
实际上@Bean注解配合方法生产对象就替代了<bean>标签,属性注入根据Name或者Type。
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
import java.util.Map;
public class TestJdbcConfig {
@Test
public void testConfigJava(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(jdbcConfig.class);
JdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);
List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from t_user");
for (Map<String, Object> map : maps) {
System.out.println(map);
}
}
}
3. Bean的生命周期
1)编写实体类,在方法上增加打印输出
package com.zt.entity;
public class Student {
private String name;
private int age;
public Student() {
System.out.println("-----构造-----");
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("-----注入name-----");
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
System.out.println("-----注入age-----");
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void init(){
System.out.println("-----初始化-----");
}
public void destory(){
System.out.println("-----销毁-----");
}
}
2)在配置文件中注册对象
<bean id="student" class="com.zt.entity.Student" init-method="init" destroy-method="destory">
<property name="age" value="22"/>
<property name="name" value="zzt"/>
</bean>
3)方法测试
@Test
public void testBean(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
System.out.println("-----获取对象前-----");
Student student = context.getBean("student", Student.class);
System.out.println(student);
context.close();
}
可见,在读取并解析配置文件的时候,Spring已经创建对象了,而容器管理的对象随着容器的销毁而销毁。注入调用setter的顺序与配置文件中定义的属性先后顺序有关。Bean的生命周期为 构造 - 注入 - 初始化 - 使用 - 销毁。
[注]:如果我们使用的是构造器注入,那么实际上就不会调用setter方法。
<bean id="student" class="com.zt.entity.Student" init-method="init" destroy-method="destory">
<constructor-arg name="age" value="22"/>
<constructor-arg name="name" value="zzt"/>
</bean>
4.Bean后置处理器
Spring提供了后置处理器,帮助我们在Bean初始化前和初始化后对Bean进行一些操作。
1)继承后置处理器类,覆写初始化前和初始化后两个方法。
package com.zt.handlers;
import com.zt.entity.Student;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class BeanHandler implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("-----初始化前处理-----");
if( bean instanceof Student ){
Student student = (Student) bean;
if("zzt".equals( student.getName() )){
System.out.println("wife");
}else if("zjm".equals( student.getName() )){
System.out.println("husband");
}
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("-----初始化后处理-----");
return bean;
}
}
2)在Spring容器中注册,由于我们本身不需要使用这个后置处理器对象,因此直接给出class即可,无需bean id。
<bean id="student" class="com.zt.entity.Student" init-method="init" destroy-method="destory">
<property name="age" value="22"/>
<property name="name" value="zzt"/>
</bean>
<bean class="com.zt.handlers.BeanHandler"/>
3)测试调用
public class BeanLife {
@Test
public void testBean(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
System.out.println("-----获取对象前-----");
Student student = context.getBean("student", Student.class);
System.out.println(student);
context.close();
}
}
[注]:这有点类似于拦截器,一旦注入Spring容器后,它会自动拦截所有的bean,并调用我们覆写的方法。
完整的Bean生命周期为 构造 - 注入 - 初始化前 - 初始化 - 初始化后 - 使用 - 销毁。