log4j.properties样板(用于配置控制台输出信息)
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n
log4j.category.org.springframework.beans.factory=DEBUG
Spring中如果要把Log4J和默认的JCL依赖( commons-logging )一起使用,你只需要 将Log4J放在类路径下并提供一个配置文件( log4j.properties 或者 log4j.xml 放在类路径的根目录下)
基于XML的配置元数据的基础结构(用于声明配置Bean)
<?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="..." class="...">
<!-- 在这里写 bean 的配置和相关引用 -->
</bean>
<bean id="..." class="...">
<!-- 在这里写 bean 的配置和相关引用 -->
</bean>
<!-- 更多bean的定义写在这里 -->
</beans>
例如:
service.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">
<!-- services -->
<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="itemDao" ref="itemDao"/>
<!-- 在这里写额外的bean的配置和相关引用 -->
</bean>
<!-- 更多Service层的bean定义写在这里 -->
</beans>
dao.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="accountDao"
class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
<!-- 在这里写额外的bean的配置和相关引用 -->
</bean>
<bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
<!-- 在这里写额外的bean的配置和相关引用 -->
</bean>
<!-- 更多数据访问层的bean定义写在这里 -->
</beans>
id属性是一个用来识别每一个独立bean定义的字符串。class属性定义了bean的类型,这个属性需要使用bean类的全限定名称。id属性的值可以被其他的bean对象引用
id和ref的关系表达出了这两个对象间的依赖关系
实例化Spring IoC容器很容易。将一个或多个位置路径提供给ApplicationContext的构造方法就可以让容器加载配制元数据,可以从多种外部资源进行获取,例如文件系统、Java的CLASSPATH等等。
使用应用上下文的构造方法从多个XML片段中加载bean的定义
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
外部的bean定义从services.xml、messageSource.xml和themeSource.xml这三个文件中加载。些被引入文件的内容会被导入进来,包含顶层的<beans/>元素,它必须是一个符合Spring架构的有效的XML bean定义。
实例化容器
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
使用容器
// 创建并配置beans
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
// 取得配置的实例
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// 使用实例
List<String> userList = service.getUsernameList();
ApplicationContext是智能的工厂接口,它能够维护注册不同beans和它们的依赖。通过使用 T getBean(String name, Class<T> requiredType) 方法,你可以取得这些beans的实例。(应用程序中,不需要调用getBean()等方式获取,Spring和web框架的集成后 会为web框架组件 提供各种依赖注入的特性,你只需要通过元数据(metadata)的方式(如:通过autowiring注解)声明一个具体的bean就可以了)。
Bean的概述
一个Spring IoC容器管理了一个或者多个 beans。这些beans通过你提供给容器的配置元数据进行创建,例如通过XML形式的<bean/>定义。
在容器内本身,这些bean定义表示为BeanDefinition对象。
bean的id和name不是必须的。如果没有明确的name或者id,容器会给bean生成一个唯一的名字。 但是,如果你想通过名称引用这个bean,通过使用ref元素或Service Locator 查找,你就必须提供一个名字。
Bean的别名定义(在配置文件的合适位置定义别名)
<alias name="fromName" alias="toName"/>
id属性指定一个唯一的名称外,为了提供多个名称,需要通过name属性加以指定,所有这个名称都指向同一个bean,在某些情况下提供别名非常有用,比如为了让应用每一个组件都能更容易的对公共组件进行引用。
Bean的实例化
Bean的定义实际上就是告诉Spring怎么样创建一个或多个对象。当需要用到bean的时候,容器查看Bean的定义以及相关配置元数据 创建对象。
容器使用Class属性(通过class属性来指定对象的类型)实例化Bean的两种方式:
- 通常,容器通过反射的方式获取Class的构造方法来创建bean,就和在java代码中用new的方式创建一个对象相似。
- 不太常见的情况下,容器调用静态工厂方法创建对象。
内部类名
例如,在com.example包下有个Foo类,这里类里面有个静态的内部类Bar,这种情况下bean定义的class属性应该…
com.example.Foo$Bar
注意,使用$字符来分割外部类和内部类的名称。
Spring IoC 容器可以管理几乎所有你想让它管理的类,它不限于管理POJO。大多数Spring用户更喜欢使用POJO(一个默认无参的构造方法和setter,getter方法)。但在容器中使用非bean形式(non-bean style)的类也是可以的。比如遗留系统中的连接池,很显然它与JavaBean规范不符,但Spring也能管理它
依赖解决步骤
容器解决依赖问题通常有以下几个步骤:
- 描述所有bean的ApplicationContext 创建并根据配置的元数据初始化。配置的元数据可以通过置顶的XML,Java代码或者注解。
- 每个bean的依赖将以属性,构造器参数或者静态工厂方法的形式出现。当这些bean被创建时,这些依赖将会提供给该bean。
- 每个属性或者构造器参数既可以是一个实际的值也可以是容器中的另一个引用。
- 每个指定的属性或者构造器参数值必须能够被转换成特定的格式或构造参数所需的类型。默认情况下Spring会以String类型转换为各种内置类型,比如int,long, String, boolean等。
当Spring容器创建时容器会校验每个bean的配置。但是在bean被实际创建 前,bean的值并不会被设置。那些单例类型的bean和被设置为预安装(默认)的bean会在容器创建时与容器同时创建。Scopes是在Bean作用域中定义的。同时,另外的bean只会在被需要时创建。伴随着bean被实际创建,作为该bean的依赖和它的依赖的依赖(以此类推)会被创建和分配。注意 这些依赖之间的解决会显示迟一些
Bean的作用域
Spring 框架支持五种开箱即用的作用域,其中三种仅在基于 web 的 ApplicationContext 中使用。
- 单例作用域
当你定义一个 bean 定义,并且它的作用域为单例的,Spring IoC 容器就会精确地(exactly)创建一个(one)对象实例。这个实例被存储在一个包含很多单例 bean 的缓存中。并且所有的后来的请求和引用(all subsequent requests and references)都会返回缓存的对象
- 原型作用域
bean使用原型作用域而不是单例作用域的话,会在每次请求该bean,也就是bean被注入至另一个bean、 或通过调用Spring容器的 getBean() 方法时,创建一个新的bean实例 。 通常,对于有状态的bean使用原型作用域,无状态的bean则使用单例作用域。
与其他作用域不同的是,Spring容器不会管理原型域bean的完整生命周期:Spring容器会初始化、 配置,亦或者组装原型域的bean对象,然后交给客户端,之后就再也不会管这个bean对象了。 因此,对于bean的生命周期方法来说,尽管所有作用域的 初始化方法 都会被调用, 但是原型域bean的 销毁方法 不会 被Spring容器调用。客户端代码要自己负责销毁原型域bean 以及和bean相关的资源(特别是开销大的资源)。如果想让Spring负责这些事(销毁bean、释放资源), 就得自定义bean的后处理器 bean post-processor ,它会持用原型域bean的引用。
从某种意义上说,对于原型域bean,Spring容器代替了Java 的 new 操作符。所有在 new 之后的生命周期管理任务, 都要由客户端自行处理。
- 基本的web配置
了使用请求 request 、会话 session 和全局会话 global session 等作用域(web作用域), 在定义bean之前要做一些最基本的初始化配置。(如果使用单例和原型这类标准作用域,是 不需要 这些初始化配置的)。
具体如何组装这些初始化配置与你使用的特定的Servlet环境有关..
事实上,如果你使用Spring Web MVC ,在 DispatcherServlet 或 DispatcherPortlet 处理的请求内去访问这些作用域的bean, 那就不用做任何专门的配置:DispatcherServlet 和 DispatcherPortlet 已经帮你做了这些事情。
如果你使用的是 Servlet2.5 标准的web容器,而且请求不是由 Spring的 DispatcherServlet 处理 (例如使用了Struts或JSF),你就得注册 org.springframework.web.context.request.RequestContextListener 这一 ServletRequestListener 。 对于Servlet 3.0 以上的环境,可以通过 WebApplicationInitializer 接口以代码的方式去实现。 或者,对于比较老旧的web 容器,在 web.xml 配置文件中加入以下的声明:
<web-app>
...
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
...
</web-app>
```
又或者,如果你在配置监听器时有问题,也可以使用 RequestContextFilter 。过滤器的映射与具体的web应用有关,所以你得自行修改映射的内容。
````xml
<web-app>
...
<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>
DispatcherServlet, RequestContextListener 和 RequestContextFilter 做的事情是一样的,都是把每个http请求对象绑定到处理线程 Thread 上, 那么,请求、会话和全局会话作用域bean就可以沿着调用链继续往下走了。