一、IOC概述
Inversion of control 控制反转。
一般情况下,一个Java对象使用依赖类时,往往需要自己创建一个依赖类的对象。创建一个依赖类的对象时,可能需要检查类是否存在,类是否能安全访问等;创建依赖类的对象后,还需要管理对象的生命周期。这些操作都增加了类之间的耦合度。
IOC的核心思想就是让一个代理人(Spring容器)来统一管理对象之间的依赖关系以及对象的生命周期,代理人会主动创建对象(指明依赖注入时,文件配置注入或者注解注入)或者需要时主动找代理人要;这样Java对象的依赖关系和生命周期管理就由自己控制变为代理人控制,所以称为控制反转。
Spring实现了代理人的功能!实现具体细节有一下几点:
DI:dependency injection 依赖注入
注解注入在xml文件注入之前完成,所以xml注入会覆盖注解注入;
注解注入的使用
//@Required
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
//@Autowired
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
//@Resource等
//暂时不清楚怎么用
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
在Spring applicationContext.xml中定义以上bean等价于:
<context:annotation-config/>
<context:annotation-config/> only looks for annotations on beans in the same
application context in which it is defined. This means that, if you put
<context:annotation-config/> in a WebApplicationContext for a DispatcherServlet, it
only checks for @Autowired beans in your controllers, and not your services.
指定扫描包的路径的配置是:
<context:component-scan base-package="package,[package]" />
分隔符可以是:逗号,分号,空格,tab符,换行符;
以上配置默认包括
<context:annotation-config/>
扫描过滤器:
public enum FilterType {
ANNOTATION,
ASSIGNABLE_TYPE,
ASPECTJ,
REGEX,
CUSTOM
}
xml文件注入
配置包含bean定义的xml文件,指定给Spring容器
Spring Bean定义
class
|
bean的类
|
name
id
|
定义bean的命名
定义bean的id
|
scope
|
bean的生命周期类型
|
constructor arguments
<constructor-arg >
|
指定构造器参数
|
properties
<property >
|
指定属性的依赖bean,实现注入
|
lazy-initialization mode
lazy-init
|
true-不会预初始化,只有调用时才会被初始化
false-bean注入时初始化
默认true
|
Spring Bean工厂
DefaultListableBeanFactory
Spring bean 容器
FileSystemXmlApplicationContext
ClassPathXmlApplicationContext
GroovyWebApplicationContext
XmlWebApplicationContext
AnnotationConfigWebApplicationContext
bean资源定位器
ClassPathResource //抽象类路径的资源
FileSystemResource //抽象文件系统类的资源
bean定义接口关系
BeanDefinition<-AbstractBeanDefinition<-RootBeanDefinition
<-GenericBeanDefinition
<-ChildBeanDefinition
<-AnnotatedBeanDefinition
二、
Spring bean容器初始化的触发
初始化方法一,在应用部署文件中指定Spring监听容器启动的监听器,
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
如果没有使用监听器启动Spring的bean容器,还可以使用web.xml的servlet的启动来完成,
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
如果要指定DispatcherServlet的配置文件,参数名一定是字符串"
contextConfigLocation"
<
init-param
>
<
param-name
>
contextConfigLocation
</
param-name
>
<
param-value
>
classpath:spring-mvc.xml
</
param-value
>
</
init-param
>
web.xml中的servlet组件配置的Servlet必须继承javax.servlet.Servlet,Servlet容器在部署应用的时候会初始化指定的Servlet类。
DispatcherServlet类的实现如下:
DispatcherServlet extends FrameworkServlet...
FrameworkServlet extends HttpServletBean...
HttpServletBean extends HttpServlet...
javax.servlet.http.HttpServlet是javax.servlet.Servlet接口的实现类。
Servlet初始化的时候,HttpServletBean的init()会被执行,init()方法调用了FrameworkServlet的initServletBean()方法,该方法实现了Spring bean容器的初始化。
web.xml中组件的加载顺序:context-param -> listener -> filter -> servlet
也可以自己实现ServletContext容器启动监听器,在监听器中完成系统需要的启动插件。
Spring获取bean的方法
在B/S场景下,因为有Servlet容器,所以应该尽可能依靠Servlet容器构建bean容器。如下,
方法一
/**
* 第一种:使用ContextLoader,顶层容器加载类
* 需要依靠Servlet容器
*/
public static ApplicationContext getContext(){
return ContextLoader.getCurrentWebApplicationContext();
}
/**
* 第二种:使用WebApplicationContextUtils,从Servlet容器中获取顶层容器
* getWebApplicationContext(ServletContext sc)默认获取顶层容器
* 需要依靠Servlet容器
* @return
*/
public static ApplicationContext getContext(ServletContext context){
return WebApplicationContextUtils.getWebApplicationContext(context);
}
/**
* 第3种:自己选择容器类,这种不需要依靠Servlet容器
*/
public static ApplicationContext getContext(String[] config){
return new ClassPathXmlApplicationContext(config);
//或者
//return new FileSystemXmlApplicationContext(config);
}