SSM Chapter 08 Spring 配置补充 笔记

本章目标:

  • 掌握更多配置数据源的方法
  • 理解Bean的作用域
  • 会使用Spring自动装配
  • 会拆分Spring配置文件

1 . 灵活配置 DataSource

实现Spring 和 MyBatis 集成的过程中,我们学习了在Spring中配置数据源的方法.实际开发中,数据源还有很多灵活的配置方式可以选择.

1.1 使用属性文件配置数据源

Spring 提供的 PropertyPlaceholderConfigurer 类可以加载属性文件.在Spring 配置文件中 可以采用${…}的方式引用属性文件中的键值对.读取属性文件配置DataSource的方法如下:

在Spring的配置文件中,代码修改如下:

  1. <!--引入properties文件-->
  2. <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  3. <property name="location" value="classpath:database.properties"/>
  4. </bean>
  5. <!--配置数据源-->
  6. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
  7. <property name="driverClassName" value="${driver}"/>
  8. <property name="url" value="${url}"/>
  9. <property name="username" value="${username}"/>
  10. <property name="password" value="${password}"/>
  11. </bean>
  12. <!--省略配置sqlSessionFactoryBean-->
  13. <!--省略配置DAO 以及 业务Bean配置-->
  14. <!--省略事务管理配置-->

database.properties 属性文件内容如下:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/foo?useUnicode=true&characterEncoding=utf-8
username=root
password=root

Spring 对于PropertyPlaceholderConfigurer 这个类 还提供了一个标签, 来简化它,代码如下:

<!--引入properties文件-->
<context:property-placeholder location="database.properties"/>
<!--配置数据源-->
<bean id="dataSource" 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>
<!--省略配置sqlSessionFactoryBean-->
<!--省略配置DAO 以及 业务Bean配置-->
<!--省略事务管理配置-->

database.properties 属性内容如下:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/foo?useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=root

注意:

  • 使用<context:property-placeholder>标签时,按照上面的代码进行配置,这是Spring 4.0.4 之后的版本官方文档所规定的。建议在database.properties属性文件的键之前加入jdbc. ,以确保使用关键字时,不会抛出异常保证 。
  • 经常有开发者 在 书写${...}的前后不小心输入了一些空格,这些空格字符将和变量合并后作为属性的值,被Spring所解析,最终引发异常。因此书写配置文件的代码时,要格外认真。

> 扩展使用<util-properties/>元素

使用<util-properties/> 指定database.properties配置文件所在的位置 , 代码如下:

<!--引入properties文件-->
<util:properties id="db" location="classpath:database.properties"/>
<!--配置数据源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName" value="#{db.driver}"/>
  <property name="url" value="#{db.url}"/>
  <property name="username" value="#{db.username}"/>
  <property name="password" value="#{db.password}"/>
</bean>
<!--省略配置sqlSessionFactoryBean-->
<!--省略配置DAO 以及 业务Bean配置-->
<!--省略事务管理配置-->

注意:

使用<util-properties/>标签时,取属性文件的值时需使用#+属性文件的id.key名,例如:#{db.driver}

database.properties 属性文件内容如下:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/foo?useUnicode=true&characterEncoding=utf-8
username=root
password=root

> 扩展使用配置类的方式:

AppConfig.java代码如下:

@Configuration
@ComponentScan("cn.foo.service")
@MapperScan("cn.foo.dao")
@PropertySource("classpath:database.properties")//扫描属性文件
@EnableTransactionManagement//启动Spring管理事务
public class AppConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Bean
    public DataSource dataSource(){
        BasicDataSource dataSource = new BasicDataSource();
        //dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setDriverClassName(driver);
        //dataSource.setUrl("jdbc:mysql://localhost:3306/foo?useUnicode
        // =true&characterEncoding=utf-8");
        dataSource.setUrl(url);
        //dataSource.setUsername("root");
        dataSource.setUsername(username);
        //dataSource.setPassword("root");
        dataSource.setPassword(password);
        return dataSource;
    }
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean =
                new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource());
        sqlSessionFactoryBean.setTypeAliasesPackage("cn.foo.pojo");
        return sqlSessionFactoryBean.getObject();
    }
    @Bean
    public DataSourceTransactionManager transactionManager(){
        return new DataSourceTransactionManager(dataSource());
    }
}

1.2 使用JNDI 数据源:

如果应用部署再高性能的应用服务器(如Tomcat WebLogic等)上,我们可能更希望应用服务器本身提供的数据源.应用服务器的数据源使用JNDI方式供使用者调用.Spring为此专门提供了引用JNDI资源的 JndiObjectFactoryBean 类.

使用JNDI 的方式配置数据源,前提是必须在应用服务器上配置好数据源. 以Tomcat为例,配置数据源要把数据库驱动文件放到 Tomcat 的lib目录下,并修改Tomcat的conf 目录中的 context.xml文件,配置数据源代码如下:

<Context>
    <Resource name="jdbc/foo" auth="Container" type="javax.sql.DataSource"
    maxActive="100" maxIdle="30" maxWait="10000" username="root"
    password="root" driverClassName="com.mysql.jdbc.Driver"
    url="jdbc:mysql://localhost:3306/foo?useUnicode=true&amp;characterEncoding=utf-8"/>
</Context>

<Resouce>标签中的name属性指定了数据源的名称,要与Spring配置文件中的jndiName值 java:comp/env/ 后面的名称保持一致. 关于<Resource>标签中的其他参数的详细配置以及 参数说明可参考官网:http://tomcat.apache.org/tomcat-9.0-doc/jndi-resources-howto.html#JDBC_Data_Sources .

Spring 配置文件内容如下:

<!--通过JNDI配置DataSource-->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
  <!--将resourceRef属性设置为true可省略java:comp/env/-->
  <!--  <property name="resourceRef" value="true"/>-->
  <!--通过jndiName 指定引用 JNDI 数据源的名称-->
  <property name="jndiName" value="java:comp/env/jdbc/foo"/>
</bean>
<!--使用第二种方式配置JNDI 需要引入jee命名空间-->
<!-- <jee:jndi-lookup jndi-name="java:comp/env/jdbc/foo" id="dataSource"/> -->
<!--省略配置sqlSessionFactoryBean-->
<!--省略配置DAO 以及 业务Bean配置-->
<!--省略事务管理配置-->

使用第二种方式可参照Spring的官网https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html

02.png

详细代码如下:

<jee:jndi-lookup jndi-name="jdbc/foo" id="dataSource"/>
<!--省略配置sqlSessionFactoryBean-->
<!--省略配置DAO 以及 业务Bean配置-->
<!--省略事务管理配置-->

1.3 在web环境中测试使用JNDI获得数据源对象

  1. pom.xml文件中将项目的打包状态改为war , 并加如servlet-api的jar包 , 关键代码如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>cn.foo</groupId>
    <artifactId>ssm_ch08</artifactId>
    <!--将项目打包的状态修改为war包 -->
    <packaging>war</packaging>
    <dependencies>
    
    <!--省略其他jar包的依赖 -->
    <!--servlet-api-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>
    
    </dependencies>
    </project>
    


    因为Java Web 的 Maven 基本结构如下:
    结构说明:

    • src:源码目录
      • src/main/java:Java 源码目录
      • src/main/resources:资源文件目录
      • src/main/webapp:Web 相关目录
      • src/test:单元测试

        所以构建web项目的目录 , 需要在项目src/main目录下 , 创建webapp目录 , 并在webapp目录下创建WEB-INF目录 , WEB-INF目录中创建web.xml文件 , 内容可参照tomcat \webapps\ROOT\WEB-INF目录下的web.xml文件 .

  2. 创建UserServlet, 代码如下:

    /**
    * 测试Spring与MyBatis的整合
    */
    public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        ApplicationContext ac = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        ac.getBean(UserService.class).findUserList().forEach(System.out::println);
        //此处只为获取到业务层的数据,故省略其他业务逻辑s
        req.getRequestDispatcher("index.jsp").forward(req,resp);
    }
    }
    


    index.jsp页面如下:

  3. web.xml配置如下: ```xml <?xml version=”1.0” encoding=”UTF-8”?>

    使用JNDI数据源 jdbc/foo javax.sql.DataSource Container

    user cn.foo.web.UserServlet 1

    user *.do

    index.do

<br />关于`resource-ref`具体配置以及参数说明 可参照[官网](http://tomcat.apache.org/tomcat-9.0-doc/jndi-resources-howto.html) : `http://tomcat.apache.org/tomcat-9.0-doc/jndi-resources-howto.html` 

4.  配置tomcat , 并将项目部署到服务器中 , 运行项目 , 控制台输出信息 , 若发现控制台中文乱码 , 在配置tomcat时,找到`VM options`,添加一行字符:`-Dfile.encoding=utf-8`,并且在IDEA中点击Help,选择![image-20201102094739944.png](https://cdn.nlark.com/yuque/0/2022/png/659452/1657460365025-66eb128c-e221-45e1-95e8-14801eb7bc1d.png#clientId=u0243c6fd-2fde-4&crop=0&crop=0&crop=1&crop=1&from=ui&id=ue6ac9462&margin=%5Bobject%20Object%5D&name=image-20201102094739944.png&originHeight=24&originWidth=223&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1906&status=done&style=none&taskId=u0d2a2d5d-439a-465d-b112-4349e0b6bbe&title=),文件末尾添加一行字符:`-Dfile.encoding=utf-8`,重启IDEA,即可解决控制台中文乱码。 

<a name="fbbb2750"></a>
### > 注意:

- 若工具使用的是**IDEA** ,创建的是普通的`Web`项目 , 而不是`Maven`项目, 则必须将 Tomcat的conf目录下的context.xml文件复制一份 到 项目目录下的**META-INF**目录下,以保证**IDEA**能够扫描到该文件,同时去掉除了配置的`<Resource>`标签之外的其他标签;
- 需在Web环境下测试使用JNDI获得数据源对象.可将测试代码写在Servlet中,或者也可以使用我们后期要讲到的SpringMVC框架整合Spring 以及 MyBatis框架进行测试;

通过以上示例我们发现,通过JNDI获取的数据源代码很简洁,这充分体现了Spring追求实用,简洁的目标

<a name="7815dc5e"></a>
### > 扩展配置类:

配置类中使用JNDI获取数据源 , 代码如下:

`AppConfig.java:` 配置JNDI的第一种方式:

```java
//省略其他代码
/*配置JNDI的第一种方式:*/
@Bean
public DataSource dataSource(){
    JndiObjectFactoryBean jndiObjectFactoryBean =
            new JndiObjectFactoryBean();
    jndiObjectFactoryBean.setResourceRef(true);
    jndiObjectFactoryBean.setJndiName("jdbc/foo");
    jndiObjectFactoryBean.setProxyInterface(DataSource.class);
    try {
        // 调用 afterPropertiesSet 方法之后,才去查找 JNDI
        jndiObjectFactoryBean.afterPropertiesSet();
    } catch (NamingException e) {
        e.printStackTrace();
    }
    return ((DataSource) jndiObjectFactoryBean.getObject());
}
//省略其他代码

AppConfig.java: 配置JNDI的第二种方式:

/**
 * 第二种方式
 * @return
 */
@Bean
public JndiObjectFactoryBean jndiObjectFactoryBean(){
    JndiObjectFactoryBean jndiObjectFactoryBean =
            new JndiObjectFactoryBean();
    jndiObjectFactoryBean.setResourceRef(true);
    jndiObjectFactoryBean.setJndiName("jdbc/foo");
    jndiObjectFactoryBean.setProxyInterface(DataSource.class);
    return jndiObjectFactoryBean;
}

/**
 *  注入 JndiObjectFactoryBean 实例化后的 bean,再获取 DataSource
 * @return
 */
@Bean
public DataSource dataSource(){
    return ((DataSource) jndiObjectFactoryBean().getObject());
}

推荐使用第二种 , 原因在于:JndiObjectFactoryBean 真正的 lookup jndi 是在Spring获取JndiObjectFactoryBean实例化的bean后,再调用 JndiObjectFactoryBean 的 afterPropertiesSet 方法去完成的。

2 . Spring 中 Bean 的作用域问题

2.1 理解 Bean 的作用域问题

在Spring中定义Bean,除了可以创建Bean实例并对Bean属性进行注入外,还可以为所定义的Bean指定一个作用域.这个作用域的取值决定了Spring创建该组件实例的策略,进而影响程序的运行效率和数据安全,在Spring 2.0 以及之后的版本中,Bean的作用域被划分为5种,如图所示:

作用域 说 明
singleton 默认值。Spring以单例模式创建Bean的实例,即容器中该Bean的实例只有一个
prototype 每次从容器中获取Bean时,都会创建一个新的实例
request 用于Web应用环境,针对每次HTTP请求都会创建一个实例
session 用于Web应用环境,同一个会话共享同一个实例,不同的会话使用不同的实例
global session 仅在Portlet的Web应用中使用,同一个全局会话共享一个实例。对于非Portlet环境,等同于session

singleton 是默认采用的作用域,即默认情况下Spring为每个Bean仅创建一个实例.对于不存在线程安全问题的组件,采用这种方式可以大大减少创建对象的开销,提高运行效率.

而对于存在线程安全问题的组件,则不能使用singleton模式,可以使用prototype作用域,通过scope属性,关键代码如下:

<!-- 指定Bean的作用域为prototype -->
<bean id="...." class="...." scope="prototype">
  .....
</bean>

这样 Spring 在每次创建该组件时,都会创建一个新的实例,避免因为共用同一个实例而产生线程安全问题.

对于web环境下使用request,session,global session 作用域,其配置细节会在后续课程中用到时再详细讲解,这里先做一下了解即可.

2.2 使用注解指定Bean的作用域

对于使用注解声明的Bean组件, 如需修改其作用域,可以使用@Scope 注解实现.关键代码如下:

@Scope("prototype")
//@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class UserServiceImpl implements UserService {
    //省略其他代码
}

3 . Spring 的自动装配

之前章节中介绍通过@Autowired @Resource 注解实现依赖注入时,曾经提到Spring的自动装配功能.在没有显式指定所依赖的Bean组件id的情况下,通过自动装配,可以将与属性类型相符的(对于@Resource注解而言还会尝试id和属性名相符的)Bean自动注入给属性,从而简化配置;

不仅通过注解实现依赖注入时可以使用自动装配,基于XML的配置中也同样可以使用自动装配简化配置.

采用传统的XML方式配置Bean组件的代码如下所示:

<!-- 省略 DataSource 和 SqlSessionFactoryBean的配置-->
<!-- 配置DAO  -->
<bean id="userMapper" class="cn.foo.dao.user.impl.UserMapperImpl">
  <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<!--配置业务Bean 并注入 DAO 实例-->
<bean id="userService" class="cn.foo.service.user.impl.UserServiceImpl">
  <property name="userMapper" ref="userMapper"/>
</bean>

在这里,我们通过<property>标签为Bean的属性注入所需要的值,当需要维护的Bean组件以及需要注入的属性增多时,势必会增加配置的工作量.

使用自动装配修改配置代码,配置文件代码如下:

<!-- 省略 DataSource 和 SqlSessionFactoryBean的配置-->
<bean id="dataSource" 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>
<!--配置sqlSessionFactoryBean-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <!--引用数据源组件-->
  <property name="dataSource" ref="dataSource"/>
  <!--引用MyBatis配置文件中的配置-->
  <property name="configLocation" value="classpath:mybatis-config.xml"/>
  <!--为实体类 指定映射别名-->
  <!--<property name="typeAliasesPackage" value="cn.foo.pojo"/>-->
  <!--配置SQL映射文件的信息 不使用mapper-->
  <property name="mapperLocations" 
            value="classpath*:cn/foo/dao/**/*.xml" />
</bean>
<!--配置DAO 根据属性名称自动装配-->    
<bean id="userMapper" 
      class="cn.foo.dao.user.impl.UserMapperImpl"
      autowire="byName" />    
<!--配置业务Bean 根据属性名称自动装配-->
<bean id="userService"        class="cn.foo.service.user.impl.UserServiceImpl" autowire="byName">
</bean>

通过设置<bean>元素中的autowire属性指定自动装配,代替了通过<property>标签显式指定Bean的依赖关系.这就是Spring自动装配的神奇之处,由BeanFactory 检查 XML 配置文件的内容,为Bean自动注入依赖关系,大大简化了维护Bean注入的配置.

Spring提供的4种自动装配类型autowire的属性常用的取值如表:

取值 说明
no 默认值。Spring默认不进行自动装配,必须显式指定依赖对象
byName 根据属性名自动装配。Spring自动查找与属性名相同的id,如果找到,则自动注入,否则什么都不做
byType 根据属性的类型自动装配。Spring自动查找与属性类型相同的Bean,如果刚好找到唯一的那个,则自动注入;如果找到多个与属性类型相同的Bean,则抛出异常;如果没找到,就什么也不做
constructor 和byType 类似,不过它针对构造方法。如果Spring找到一个Bean和构造方法的参数类型相匹配,则通过构造注入该依赖对象;如果找不到,将抛出异常

> 问题

在Spring配置文件中 通过<bean>元素的autowire属性可以实现自动装配.但是,如果要自动装配的Bean很多,每个Bean若都配置autowire属性,则会变得很繁琐,可不可以统一设置自动注入而不必配置每个Bean呢?

> 解决方案:

<beans>元素提供了default-autowire 属性. 可以使用上表中的属性值为<beans> 设置default-autowire属性,影响全局,减少维护单个Bean的注入方式.

修改Spring 配置文件,设置全局自动装配,代码如下:

<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
                           http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx.xsd"
       default-autowire="byName">
  <!-- 省略其他代码 -->
</beans>

<beans>节点上设置default-autowire时,<bean>节点上依然可以设置autowire属性.这时该<bean>节点上的自动装配设置将覆盖全局配置,成为该Bean的自动装配策略.

经验:

对于大型应用,不鼓励使用自动装配.虽然使用自动装配使得配置文件可以非常简洁,但同时也造成组件之间的依赖关系不明确,容易引发一些潜在的错误,所以,在实际项目中要谨慎使用

4 . 拆分Spring配置文件

为什么需要拆分配置文件?

项目规模变大,配置文件可读性、可维护性差

团队开发时,多人修改同一配置文件,易发生冲突

4.1 拆分策略

  • 公用配置 + 每个系统模块一个单独配置文件(包含DAO、Service、Web控制器)
  • 公用配置+DAO Bean配置+业务逻辑Bean配置+Web控制器配置

两种策略各有特色,适用于不同场合

4.2 拆分方法

两种方法

第一种:

利用ClassPathXmlApplicationContext的重载构造方法可以配置多个配置文件,用逗号隔开或者使用通配符

方法如下:

  • public ClassPathXmlApplicationContext(String configLocation);
  • public ClassPathXmlApplicationContext(String… configLocations);

如果有多个配置文件需要载入,可以分别传入多个配置文件,代码如下:

ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml",
                    "applicationContext-dao.xml",
                        "applicationContext-service.xml");
  //省略其他代码

使用注解:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"
        ,"classpath:applicationContext-dao.xml",
        "classpath:applicationContext-service.xml"})
public class TestUserService {
    //省略其他代码 
}

使用通配符(*)来加载多个具有一定命名规则的配置文件,代码如下:

ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("classpath*:applicationContext*.xml");
    //省略其他代码

注解通配符:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:applicationContext*.xml")
public class TestUserService {
    //省略其他代码 
}

经验:

实际项目开发过程中,建议通过通配符(*****)的方式配置多个Spring配置文件.为了方便采用通配符,建议在给Spring配置文件命名时遵循一定的规律

第二种:使用<import resource="xxx.xml"/>方式

Spring 配置文件本身也可以通过 <import> 子元素导入其他配置文件,将多个配置文件整合到一起,形成一个完整的Spring配置文件. 例如 : 在applicationContext.xml文件中添加如下代码,则只需引用applicationContext.xml即可加载所有的配置文件。

<!-- 省略其他代码 -->
<!-- 导入多个Spring 配置文件 -->
<import resource="classpath:applicationContext-dao.xml"/>
<import resource="classpath:applicationContext-service.xml"/>
<!-- 省略其他代码 -->

测试代码如下:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class TestUserService {
    private final Logger logger = Logger.getLogger(this.getClass());
    @Autowired
    private UserService userService;
    @Test
    public void testGetUserList(){
        List<User> userList = userService.findUserList();
        userList.forEach(logger :: info);
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");
         // 获取容器中定义的所有的Bean的名称      
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        logger.info(Arrays.toString(beanDefinitionNames));
    }
}

4.3 配置类实现:

AppConfig.class代码如下:

@Configuration
@MapperScan("cn.foo.dao")
@PropertySource("classpath:database.properties")//扫描属性文件
public class AppConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Bean
    public DataSource dataSource(){
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean =
                new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource());
        sqlSessionFactoryBean.setTypeAliasesPackage("cn.foo.pojo");
        return sqlSessionFactoryBean.getObject();
    }
}

AppServiceConfig.java代码如下:

@ComponentScan("cn.foo.service")
@EnableTransactionManagement//<tx:annotation-driven />
@Import(AppConfig.class)//导入配置类 代替<import resource="classpath:applicationContext-dao.xml"/>
public class AppServiceConfig {
    @Autowired
    private DataSource dataSource;
    //<!--定义事务管理器的Bean-->
    @Bean
    public TransactionManager transactionManager(){
        return new DataSourceTransactionManager(dataSource);
    }
}

测试类代码如下:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppServiceConfig.class)
public class TestUserService {
    private final Logger logger = Logger.getLogger(this.getClass());
    @Autowired
    private UserService userService;
    @Test
    public void testGetUserList(){
        List<User> userList = userService.findUserList();
        userList.forEach(logger :: info);
    }
}