1、什么是IOC
IOC是Inversion of Control的缩写,控制反转,将创建对象的实现交给spring,从而降低项目的复杂度和系统之间的耦合度。
2、web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<!-- 指定spring加载容器的类,没指定默认去加载spring-web下的ContextLoader.properties文件,使用org.springframework.web.context.support.XmlWebApplicationContex -->
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<!-- 日志配置文件 -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>
<!-- Spring相关配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/application*.xml</param-value>
</context-param>
<!-- 配置过滤器-->
<filter>
<filter-name>CharacterFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>force</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!-- 为过滤器配置映射路径-->
<filter-mapping>
<filter-name>CharacterFilter</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
<!-- Spring 容器启动监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring MVC 的Servlet,它将加载WEB-INF/testserver-servlet.xml 的
配置文件,以启动Spring MVC模块-->
<servlet>
<servlet-name>testserver</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置controller请求后缀-->
<servlet-mapping>
<servlet-name>testserver</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<session-config>
<!-- Default to 5 minute session timeouts -->
<session-timeout>10</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>/welcome.jsp</welcome-file>
</welcome-file-list>
</web-app>
application.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"
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 https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="messageService" class="org.springframework.test.web.test.service.impl.MessageServiceImpl"/>
<!-- 配置包扫描,改包下的及子包下的,有@Service注解,@Component注解的,会将对应的对象做初始化bean处理-->
<context:component-scan base-package="org.springframework.test.web.test" />
</beans>
3、IOC实现流程
容器加载监听器,容器启动后会去执行,spring初始化入口
org.springframework.web.context.ContextLoaderListener
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {
}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
/**
* 初始化web容器的入口
*/
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
/**
* Close the root web application context.
*/
@Override
public void contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
初始化web应用容器
org.springframework.web.context.ContextLoader#initWebApplicationContext
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}
servletContext.log("Initializing Spring root WebApplicationContext");
Log logger = LogFactory.getLog(ContextLoader.class);
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
try {
//创建web应用容器,如果没有配置contextClass,就读取默认的配置文件ContextLoader.properties,创建默认的容器XmlWebApplicationContext
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
//有实现ConfigurableWebApplicationContext接口,就会走这里的逻辑
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
//加载父级容器
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
//加载web.xml配置的相关spring配置和初始化bean入口,具体加载怎么加载beanDefine和bean请查看:https://blog.csdn.net/qq_38019655/article/details/140385244
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");
}
return this.context;
}
catch (RuntimeException | Error ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
}