8.1配置数据源
使用properties文件配置数据源时,可以把数据源的相关配置信息单独放到properties文件中进行维护。配置代码如下
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/cvs-db?serverTimezone=GMT-8
jdbc.username=root
jdbc.password=liuyuhan
Spring框架提供了PropertySourcesPlaceholderConfigurer类加载properties文件。在Srping配置文件中可以采用${xxx}的方式引用properties文件中的键值对数据。读取properties文件配置DataSource的代码如下
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="location">
<value>classpath:database.properties</value>
</property>
</bean>
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
注意
(1)表达式SXX)前后是没有空格的,如果开发者在其中键入了空格,这些空格字符将与变量合并后作为属性的值,最终将引发异常。
(2)单独维护数据源配置信息可以在切换应用程序运行环境时,只对数据源配置文件做修改,避免修改Spring配置文件。
8.1.2使用JNDI配置数据源
如果应用程序所部署的服务器(如 Tomcat、WebLogic 等)提供了数据源服务,应用程序也可以直接使用这些数据源。服务器数据源是使用JNDI方式,Spring框架为此专门提供了引用JNDI资源的JndiObjectFacto1yBean类供开发者使用。
若使用JNDI方式配置数据源,则需要把数据源信息配置到应用服务器上。以 Tomcat 为例,首先,需要把数据库驱动文件放到 Tomcat 的 lib 目录下,然后,把数据源信息配置到 Tomcat的conf目录下的contextxml 文件中,并修改Spring配置文件为通过JNDI方式配置数据源。具体配置信息如下所示
<Resource name="jdbc/cvs_db"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="root"
password="liuyuhan"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/cvs_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai"/>
Spring 配置文件:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/cvs_db</value>
</property>
</bean>
8.2拆分Spring配置文件
如果选择使用XML 配置文件的方式开发 Spring 项目,则当项目规模越来大时,项目中的Bean 也越来越多,配置文件将变得越来越臃肿,可读性和维护性都会降低;多人修改同一配置文件时也容易发生冲突,影响开发效率。因此,Spring 框架提供了可以将配置文件拆分处理的功能,可以将一个大的配置文件分解成多个小配置文件,如下所示。
以上每个配置文件仅仅配置功能类似的 Bean。配置文件拆分完成之后,就需要在创建Spring容器时加载这些文件。Spring框架的ClassPathXmlApplicationContext类提供了多种重载形式,便于从多个配置文件中读取配置信息,如图下所示。
publ1c ClassPathxmlApplicationContext(String configlocation) throws BeansException [...]
public ClassPathXmlApplicationContext(String... configlocations) throws BeansException (...]
ClassPathXmlApplicationContext提供了可传入动态参数的构造方法如果有多个配置文件需要载入,可以以多个字符串参数或 String 口数组的形式传入多个配置文件名,也可以以通配符的形式进行传参,如下所示。
多个参数方式:
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"ApplicationContext.xml",
"ApplicationContext-dao.xml",
"ApplicationContext-service.xml");
数组参数方式:
String[] configs = {"ApplicationContext.xml",
"ApplicationContext-dao.xml",
"ApplicationContext-service.xml",}
ApplicationContext ctx = new ClassPathXmlApplicationContext(configs)
通配符参数方式:
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"ApplicationContext*.xml");
除使用ClassPathXmlApplicationContext的构造方法加载多个配置文件外,Spring还提供了再配置文件中通过import标签直接加载其他配置文件的功能,如在applicationContext.xml中加载ApplicationContext-dao.xml,ApplicationContext-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"
xmlns:context="http://www.springframework.org/schema/context"
...... //其他代码省略
http://www.springframework.org/schema/beans/spring-beans.xsd"
<import resource="applicationContext-dao.xml"/>
<import resource="applicationContext-service.xml"/>
8.3 Bean 的自动装配
学习@Autowired 或@Resource 注解的时候同学们已经对 Spring 框架的自动装配功能有了一定的了解。Spring 框架的自动装配是指在没有显式指定所依赖的 Bean 组件 id 的情况下,可以自动地将与属性类型相符的 Bean 注入相应属性的功能(对于@Resource 注解而言,还会尝试id和属性名相符的情况),这在很大程度上简化了配置。
Spring 框架除支持注解方式的自动装配功能外,还支持使用 XML 配置文件方式实现 Bean的自动装配
<bean id="supplierMapper" class="com.bdqn.mapper.impl.SupplierMapperImpl" autowire="byType" />
<bean id="SupperService" class="com.bdqn.service.impl.SupplierServiceImpl" autowire="byName"/>
随着业务的发展,项目规模越来越大,需要在配置文件中维护的 Bean 组件及注入的属性也越来越多,这不仅给开发人员带来了大量的工作。还让系统变得难以维护。这时,就需要使用自动装配的方式来解决问题了,关键代码如下所示。
<bean id="supplierMapper" class="com.bdqn.mapper.impl.SupplierMapperImpl" autowire="byType" />
<bean id="SupperService" class="com.bdqn.service.impl.SupplierServiceImpl" autowire="byName"/>
在上面代码中去掉了property 标签的相关代码,取而代之的是在 bean 标签中添加了一个autowire 属性。其中,autowire="byName”表示根据属性名自动进行组件的装配,由 BeanFactory检查XML配置文件内容,为Bean 自动注入依赖、关系。
Spring框架提供了多种自动装配方式,如下所示。
1.no:不使用自动装配。Bean 的依赖、关系必须通过 property 元素定义。
2.byType: 根据属性类型自动装配。BeanFactorv 查找容器中的全部 Bean,如果正好有-个与依赖属性类型相同的 Bean.则自动装配这个属性;如果有多个这样的 Bean,则Spring将无法决定注入哪个 Bean,会抛出一个致命异常;如果没有匹配的 Bean,则什么都不会发生,属性不会被设置。
3.byName:根据属性名自动装配。BeanFactory 查找容器中的全部 Bean,找出id与属性的setter方法匹配的 Bean。找到即自动注入,否则什么都不做。
4.constructor:与byType 的方式类似,不同之处在于,它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的 Bean,将会抛出异常。在Spring配置文件中可以通过配置 bean 标签中的 autowire 属性实现 Bean 的自动装配功能。
想象一下,如果需要配置的Bean很多,为每个Bean都配置 autowire 属性是不是也烦琐?似乎需要写很多重复的代码,能不能为这些 Bean 进行统一的配置呢?
答案是肯定的,Spring 框架提供了为 Bean 统一配置自动装配的功能,代码非常简单,如下所示。
8.4 Bean的作用域
在Spring框架中定义Bean,除可以创建Bean实例并对 Bean 的属性进行注入外,还可以所定义的Bean 指定一个作用域,这个作用域的取值决定了 Spring 框架创建该组件实例的策略,进而影响程序的运行效率和数据安全。在 Spring2.0 及之后的版本中,Bean 的作用域被划分以下五种。
> singleton: 默认值。以单例模式创建 Bean 的实例,即容器中该 Bean 的实例只会被创建一个。
> prototype: 每次从容器中获取 Bean 时,都会创建一个新的实例。
> request;用于Web应用环境,针对每次HTTP 请求都会创建一个实例。
> Sesion: 用于web 应用环境,同一个会话共享同一个实例,不同的会话使用不同的实
例。
> global session;仅在portlet 的web 应用中使用,同一个全局会话共享一个实例。对非Poltlet环境,等同于 session。
singleton 是默认的作用域,表示在默认情况下 Spring 架为每个 Bean 仅创建一个实例采用这种方式可以大大减少创建对象的开销,提高运行效率。但是,对于存在线程安全问题组件,可以使用 prototype作用域代替单例模式,关键代码如下所示。
<bean id="supplierMapper" class="com.bdqn.mapper.impl.SupplierMapperImpl" autowire="byType" scope="singleton"/>
<bean id="SupperService" class="com.bdqn.service.impl.SupplierServiceImpl" autowire="byName" scope="prototype"/>