Spring容器是Spring的核心,是生成Bean
的工厂。Spring有两个核心接口:BeanFactory
和ApplicationContext
,后者是前者的子接口,二者都可以代表Spring容器。
ApplictionContext
的实现类有:
FileSystemXmlApplicationContext
: 基于文件系统的XML配置文件创建ApplicationContext
ClassPathXmlApplicationContext
: 基于类加载路径下的xml配置文件创建ApplicationContext
所以一般可以这样创建Spring容器:
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
//或者
ApplicationContext context = new FileSystemXmlApplicationContext("file:绝对路径/spring.xml");
依赖注入的方式主要有2种:
Bean
属性的setter
方法注入(前提是有setter方法)Bean
的构造方法注入(前提是有构造方法) <!-- 通过 setter 方法注入 -->
<bean id="helloService" class="com.test.spring.service.impl.HelloServiceImpl">
<property name="hello" ref="hello"/> <!-- 若参数不是自定义类型,则使用value="**"的方式 -->
</bean>
<!-- 通过构造方法注入 -->
<bean id="helloService" class="com.test.spring.service.impl.HelloServiceImpl">
<!-- 下面着四种注入方式,只要一种就可以,最好通过name或者index来注入 -->
<constructor-arg ref="hello" /> <!-- 当构造方法有多个参数时,这样会有问题 -->
<constructor-arg name="hello" ref="hello" /> <!-- 通过参数名称注入 -->
<constructor-arg index="0" ref="hello" /> <!-- 通过参数索引注入 -->
<constructor-arg type="com.test.spring.dao.Hello" ref="hello" /> <!-- 通过参数类型注入 -->
<!-- 通过参数类型注入的其他例子 -->
<!--<constructor-arg type="java.lang.Double" value="100.00" />-->
</bean>
<bean id="hello" class="com.test.spring.dao.impl.HelloImpl" scope="singleton"></bean>
bean
元素的scope
属性主要是用来指定如何创建bean
对象的,系统已经实现的主要有五中类型,分别是:singleton
、prototype
、request
、session
和globalSession
。
其中request
、session
和globalSession
只能在web环境中使用,当在非web环境中使用它们时,系统会抛出IllegalStateException
异常。
singleton
: 默认值,单例模式。在整个Spring IoC容器中只会创建一个对象,该对象创建以后是保存在singleton beans
的缓存中的,每次都取得同一个bean
对象。prototype
: 原型模式。每次通过容器的getBean
方法获取prototype
定义的Bean
时,都将产生一个新实例。request
: 对每次HTTP request
都将产生一个新实例。session
: 对每个处于活跃状态的HttpSession
都将创建一个对象。globalSession
: 一个全局的HttpSession
下会拥有一个单独的实例,通常用于Portlet环境下。注意:
singleton
的bean A
依赖于一个prototype
的bean B
时,A拥有的B就只会在A初始化时初始化一次,每次在A使用B的时候都是用的同一个对象B,这与B为prototype
有点违背,不是我们想要的结果,其解决办法是,使bean A
实现一个ApplicationContextAware
接口,在每次A需要使用B的时候都从ApplicationContext
里面取一个B对象,这个时候取的B对象每次都会是不一样的。http
级别的scope
的对象注入到其他bean
中时,需要在声明的http
级别的scope
的对象中加入<aop:scoped-proxy/>
如下面的userPreferences对象 <bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<!-- <aop:scoped-proxy/> -->
<aop:scoped-proxy proxy-target-class="false"/><!-- 为true则为开启对CGLIB的支持 -->
</bean>
<bean id="userService" class="com.foo.SimpleUserService">
<property name="userPreferences" ref="userPreferences"/>
</bean>
这样做的原因就像在singleton
的Bean
中引用了prototype
的Bean
一样,而使用<aop:scoped-proxy/>
就会在实际调用的时候每次使用代理去代理userPreferences
调用其对应的方法,代理访问的是对应的session
中的对象,这样就可以实现每个session
对应一个对象。而在代理的时候有两种方式,一种是基于JDK的interface的,一种是CGLIB形式的,如果要代理的类是面向对象的,就可以直接使用JDK的代理,否则就需要开启对CGLIB代理的支持,同时要引入CGLIB的jar包。
request
、session
和globalSession
只在Web环境中, 并且在Web应用中增加了额外的配置(将HTTP请求对象绑定到为该请求提供服务的线程上)才会生效。具体做法是:servlet2.4+
的容器,则需要在web.xml
中加入一个RequestContextListener
监听器servlet2.4
之前规范的容器,则该容器不支持Listener
规范,故无法使用这种配置, 需要在web.xml
中加入一个RequestContextFilter
Spring MVC
作为MVC框架,则无需这些额外的配置,因为SpringDispatchServlet
或DispatchPortlet
已经处理了所有和请求有关的状态处理。<web-app>
...
<!-- 支持servlet2.4及以上 RequestContextListener -->
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
<!-- 仅支持servlet2.4之前 RequestContextFilter -->
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>