Spring测试环境搭建
Spring模块概览,Spring中八大模块,黑色表示该模块的jar包(也就是组件)。例如我们想要使用IOC容器,也就是绿色的CoreContainer,我们需要导入Beans,Core,Context,SpEL(spring-expression)四个包。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.13</version>
</dependency>
resources下面新建beans.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="mysqlImpl" class="com.lv.dao.UserDaoMysqlImpl"/>
<bean id="oracleImple" class="com.lv.dao.UserDaoOracleImpl"/>
<bean id="UserServiceImpl" class="com.lv.service.UserServiceImpl">
<property name="userDao" ref="mysqlImpl"></property>
</bean>
<!--
ref :引用Spring容器中创建好的对象
value:具体的值,基本数据类型
-->
</beans>
java下建dao包 分别创建下面几个类
public interface UserDao {
void getUser();
}
public class UserDaoImpl implements UserDao{
public void getUser(){
System.out.println("默认");
}
}
java下建service包分别创建下面几个类
public interface UserSerivce {
void getUser();
}
public class UserServiceImpl implements UserSerivce {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser(){
userDao.getUser();
}
}
test目录下建MyTest
// 导包的时候记着导junit
public class MyTest {
@Test
public void getUser(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("UserServiceImpl");
userServiceImpl.getUser();
}
}
1.2容器创建过程
从测试类的ApplicationContext context = new ClassPathXmlApplicationContext(“beans.xml”);
进入ClassPathXmlApplicationContext
/*
configLocations: 是xml的名字
refresh :是否自动刷新上下文、加载所有bean定义和创建所有单例。或者,在进一步配置上下文之后,手动调用REFRESH。
parent: 父类上下文 也就是父容器
*/
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
// 保存父容器,并将父容器的环境与当前容器环境合并。
super(parent);
// 设置配置文件路径
setConfigLocations(configLocations);
if (refresh) {
// 核心步骤
refresh();
}
}
加载配置文件后,进入AbstractApplicationContext 的refresh()方法,该方法是容器初始化的核心步骤。该方法包含十三个方法:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 容器启动的状态
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// Prepare this context for refreshing
// 准备刷新,做一些最基本的准备化工作
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 获得一个刷新的bean容器,实质就是获取工厂。
// 加载xml等配置文件,用该文件产生的BeanDefinition来创建一个工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 准备bean工厂
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 后置增强 AOP,方便扩展
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
// 实例化和调用所有 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 实例化并且注册所有的BeanPostProcessor
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// Initialize message source for this context.
// 国际化设置,一般不用
initMessageSource();
// Initialize event multicaster for this context.
// 初始化事件监听多路广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 空方法,预留给子类做扩展。对于子类:默认情况下不做任何操作。
onRefresh();
// Check for listener beans and register them.
// 注册监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所有非懒加载的实例对象
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 发布相应事件 完成刷新
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
// 销毁已经创建的单例避免资源浪费
destroyBeans();
// Reset 'active' flag.
// 重启 active 标记
cancelRefresh(ex);
// Propagate exception to caller.
// 抛出异常
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
// 重置Spring核心中的常见内核缓存,因为我们可能不再需要单例bean的元数据了
resetCommonCaches();
contextRefresh.end();
}
}
}
接下来我们一个一个看,一个一个具体方法分析:
PrepareRefresh: 准备刷新,做一些基本的准备工作
/**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
*/
protected void prepareRefresh() {
// Switch to active.
// 设置开始事件
this.startupDate = System.currentTimeMillis();
// 关闭状态设置为false
this.closed.set(false);
// 活跃状态设置为true
this.active.set(true);
// 日志打印
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment.
// 初始化上下文属性资源
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
// 获取环境 验证上下文需要的属性信息
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
// 存储预刷新的一些应用信息的监听器
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
// 将本地应用程序监听器重置为与刷新状态
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
// 创建一些监听器事件的集合
this.earlyApplicationEvents = new LinkedHashSet<>();
}
总结:
perpareRefresh()方法
1.设置启动事件
2.设置关闭、活跃的状态
3.初始化属性资源、获取环境信息并验证属性信息
4.设置监听器、重置本地应用的监听器状态以及创建监听事件的集合
重要的点:
- 获取环境信息,验证属性信息 getEnvironment().validateRequiredProperties();
- 存储预刷新的一些应用信息的监听器,在Spring中是空实现,但是SpringBoot中,是由具体的值的