Spring(二): 基本用法
Spring容器
Spring容器是Spring的核心,是生成Bean的工厂。Spring有两个核心接口:BeanFactory和ApplicationContext,后者是前者的子接口,二者都可以代表Spring容器。ApplictionContext的实现类有:
FileSystemXmlApplicationContext: 基于文件系统的XML配置文件创建ApplicationContextClassPathXmlApplicationContext: 基于类加载路径下的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的scope属性
<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 - 若Web应用直接使用
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>