spring配置数据源和注解开发


今天学习内容是如何使用spring核心配置文件配置数据源,以及学习如何进行spring注解开发。通过使用spring配置数据源,可以将一些参数以key-value的形式保存在properties文件中,将代码和一些参数解耦,修改参数时不需要修改代码。spring注解开发的目的是通过在代码中使用注解,来避免繁杂的xml文件配置。注解开发分为原始注解和新注解,原始注解无法替代某些xml配置,而新注解可以解决这些问题使得开发可以完全脱离xml文件配置。

配置数据源(数据库连接池)

  • pom.xml配置文件添加mysql和c3p0依赖
    <dependency>
    	<groupId>mysql</groupId>
    	<artifactId>mysql-connector-java</artifactId>
    </dependency>
    
    <dependency>
    	<groupId>com.mchange</groupId>
    	<artifactId>c3p0</artifactId>
    	<version>0.9.5.5</version>
    </dependency>
    
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.5</version>
    </dependency>
    

手动获取数据源

  • 测试手动连接c3p0数据源和druid数据源
    package com.example.datasource;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import org.junit.Test;
    
    import java.sql.Connection;
    
    
    public class DataSourceTest {
        @Test
        // 手动测试c3p0数据源示例
        public void testC3P0() throws Exception {
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
            dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");  // 需要提前创建好本地test数据库
            dataSource.setUser("root");
            dataSource.setPassword("root");
            Connection connection = dataSource.getConnection(); // 获取一个连接
            System.out.println(connection);
            connection.close();     // 释放连接
        }
    
        @Test
        // 手动测试druid数据源示例
        public void testDruid() throws Exception {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost:3306/test");
            dataSource.setUsername("root");
            dataSource.setPassword("root");
            Connection connection = dataSource.getConnection();
            System.out.println(connection);
            connection.close();
        }
    }
    
  • 使用properties文件配置数据库连接相关参数,对代码和参数进行解耦,更改参数不需要更改代码
    // jdbc.properties
    jdbc.driver=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/test
    jdbc.username=root
    jdbc.password=root
    
    @Test
        public void testPropertyFile() throws Exception {
            ResourceBundle rb = ResourceBundle.getBundle("jdbc");
            String driver = rb.getString("jdbc.driver");
            String url = rb.getString("jdbc.url");
            String username = rb.getString("jdbc.username");
            String password = rb.getString("jdbc.password");
    
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setDriverClass(driver);
            dataSource.setJdbcUrl(url);
            dataSource.setUser(username);
            dataSource.setPassword(password);
            Connection connection = dataSource.getConnection();
            System.out.println(connection);
            connection.close();
        }
    

spring配置数据源

  • 将DataSource创建权交给spring容器
  • 配置xml文件
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
    </bean>
    
  • 继续将xml中dataSource的属性与其对应值解耦,更改参数值只需更改数据源的jdbc.properties文件
  • 需要在applicationContext文件中引入context命名空间和约束路径
    xmlns:context="http://www.springframework.org/schema/context"
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd
    
  • 修改xml文件
    <!-- 导入properties文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
  • 测试代码
    @Test
    public void testSpringConfig() throws Exception{
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        ComboPooledDataSource dataSource = (ComboPooledDataSource) app.getBean("dataSource");
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        connection.close();
    }
    

spring注解开发

  • spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率

spring原始注解

注解类型

  • 实例化注解
    • @Component
      • 可以使用此注解描述 Spring 中的 Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次使用时只需将该注解标注在相应类上即可
    • @Repository
      • 用于将数据访问层(DAO层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同
    • @Service
      • 通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同
    • @Controller
      • 通常作用在控制层(如 Struts2 的 Action),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同
  • 依赖注入注解
    • @Autowired
      • 用于对 Bean 的属性变量、属性的 Set 方法及构造函数进行标注,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配
    • @Qualifier
      • 与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定
    • @Resource
      • 相当于@Autowired+@Qualifier,其作用与@Autowired 一样。其区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 实例名称进行装配
      • @Resource 中有两个重要属性:name 和 type
      • Spring 将 name 属性解析为 Bean 实例名称,type 属性解析为 Bean 实例类型如果指定 name 属性,则按实例名称进行装配如果指定 type 属性,则按 Bean 类型进行装配
      • 如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常
    • @Value
      • 注入普通属性
  • Scope
    • 标注Bean的作用范围
  • PostConstruct
    • 使用在方法上标注该方法是Bean的初始化方法
  • PreDestroy
    • 使用在方法上标注该方法是Bean的销毁方法

注解组件扫描

  • 使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法
    <!-- 注解组件扫描 -->
    <context:component-scan base-package="com.example"></context:component-scan>
    

注解开发简单示例

  • 定义Dao接口和实现类
    package com.example.anno.dao;
    
    public interface UserDao {
        public void save();
    }
    
    package com.example.anno.dao.impl;
    
    import com.example.anno.dao.UserDao;
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Repository;
    
    // <bean id="userDao" class="com.example.anno.dao.impl.UserDaoImpl"></bean>
    // 括号内字符串相当于id
    @Repository("userDao")
    public class UserDaoImpl implements UserDao {
        @Override
        public void save() {
            System.out.println("UserDaoImpl save running");
        }
    }
    
  • 定义Service接口和实现类
    package com.example.anno.service;
    
    public interface UserService {
        public void save();
    }
    // ---------------------------------------
    package com.example.anno.service.impl;
    
    import com.example.anno.dao.UserDao;
    import com.example.anno.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    // <bean id="userService" class="com.example.anno.service.impl.UserServiceImpl"/>
    @Service("userService")
    @Scope("prototype")
    @PropertySource("classpath:jdbc.properties")
    public class UserServiceImpl implements UserService {
    
        // <property name="userDao" ref="userDao">
        // 依赖注入,@Qualifier指定注入类型名称
    
        @Autowired  // 按照数据类型自动从spring容器中进行匹配注入
        @Qualifier("userDao")   // 按照id值在spring中进行匹配,仅按照类型注入可以省去,按照名称注入不可省去
        // @Resource(name = "userDao") // 相当于@Autowired + @Qualifier
        private UserDao userDao;    // 采用注解开发的方法,可以不写setter方法
    
        @Value("${jdbc.url}")     // 从properties文件中找到key对应的value赋给字段
        private String url;
    
        @PostConstruct
        public void init(){
            System.out.println("initializing...");
        }
    
        @PreDestroy
        public void destroy(){
            System.out.println("destroying...");
        }
    
        @Override
        public void save() {
            userDao.save();
            System.out.println(url);
            System.out.println("UserServiceImpl save running");
        }
    }
    
  • 定义测试类
    package com.example.anno;
    
    import com.example.anno.service.UserService;
    import org.junit.Test;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class AnnoTest {
        @Test
        public void test(){
            ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
            UserService userService = (UserService) app.getBean("userService");
            userService.save();
            app.close();
        }
    }
    

spring新注解

  • 使用原始注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
    • 非自定义的Bean的配置:<bean>
    • 加载的properties文件的配置:<context:property-placeholder>
    • 组件扫描的配置:<context:conponent:scan>
    • 引入其他xml配置文件:<import>

新注解类型

  • @Configuration
    • 指定当前类时一个spring配置类,当创建容器时会从该类上加载注解
  • @ComponentScan
    • 用于指定spring在初始化容器时要扫描的包
    • 作用和用在spring的xml配置文件中的<context:conponent:scan base-package="...">一样
  • @Bean
    • 使用在方法上,标注将该方法的返回值存储到spring容器中。它就相当于xml配置中的factory-bean和factory-method。name属性:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)
  • @PropertySource
    • 用于加载.properties文件中的配置,相当于<context:property-placeholder>
  • @Import
    • 用于导入其他配置类

新注解开发示例

  • 编写新注解数据源配置类,代替xml配置
    package com.example.springconfig;
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    import java.beans.PropertyVetoException;
    
    @Configuration // 标志该类是一个spring配置类
    @ComponentScan("com.example.springconfig")  // 相当于<context:component-scan base-package="com.example.springconfig"/>
    @PropertySource("classpath:jdbc.properties") // 相当于<context:property-placeholder location="classpath:jdbc.properties"/>
    public class DataSourceConfig {
        /*
        以下代码相当于
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.driver}"/>
            <property name="jdbcUrl" value="${jdbc.url}"/>
            <property name="user" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </bean>
        */
        @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("dataSource") // 将方法返回值以指定名称(dataSource)加入spring容器中
        public ComboPooledDataSource getDataSource() throws PropertyVetoException {
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setDriverClass(driver);
            dataSource.setJdbcUrl(url);
            dataSource.setUser(username);
            dataSource.setPassword(password);
            return dataSource;
        }
    }
    
  • 将上述数据源配置类导入到配置汇总类
    package com.example.springconfig;
    import org.springframework.context.annotation.Import;
    
    @Configuration
    @ComponentScan("com.example.springconfig")
    @Import(DataSourceConfig.class) // 将配置好的类加载到本类中,相当于将其他子xml文件import到主xml文件
    public class SpringConfig {
    }
    
  • 测试类
    package com.example.springconfig;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import org.junit.Test;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    
    public class SpringConfigTest {
        @Test
        public void test() throws SQLException {
            // 使用注解配置的ApplicationContext,加载主配置类SpringConfig
            AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SpringConfig.class);
            ComboPooledDataSource dataSource = (ComboPooledDataSource) app.getBean("dataSource");
            Connection connection = dataSource.getConnection();
            System.out.println(connection);
            connection.close();
        }
    }
    

spring集成Junit

  • 让spring Junit负责创建spring容器,但是需要将配置文件的名称告诉Junit
  • 将需要进行测试的Bean直接在测试类中进行注入

集成Junit步骤

  • 导入spring集成Junit的坐标
  • 使用@Runwith注解替换原来的运行期
  • 使用@Autowired注入要测试的对象
  • 创建测试方法进行测试

示例

  • pom.xml导入依赖
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
    </dependency>
    
  • 集成Junit测试代码
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    //@ContextConfiguration("classpath:applicationContext.xml") // 使用配置文件
    @ContextConfiguration(classes = {UserServiceImpl.class, UserDaoImpl.class})  // 使用全注解方式,注入要测试的对象
    public class SrpingJunitTest {
        @Autowired
        private UserServiceImpl userService;
    
        @Autowired
        private UserDaoImpl userDao;
    
        @Test
        public void test(){
            userService.save();
            userDao.save();
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值