Spring配置数据源和注解开发
Spring配置数据源
数据源(连接池)的作用
数据源(连接池)是提高程序性能如出现的
事先实例化数据源,初始化部分连接资源
使用连接资源时从数据源中获取
使用完毕后将连接资源归还给数据源
常见的数据源(连接池):DBCP、C3P0、BoneCP、Druid等
开发步骤
①导入数据源的坐标和数据库驱动坐标
②创建数据源对象
③设置数据源的基本连接数据
④使用数据源获取连接资源和归还连接资源
现在spring项目中的pom中导入jar包坐标
<!-- 导入第三方jar包--> <dependencies> <!-- 导入Spring的jar 包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.3.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--导入数据源连接需要的jar包--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.32</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.9</version> </dependency> </dependencies>
手动创建c3p0的数据源
@Test //手动创建c3p0的数据源 public void testTwo() throws Exception { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/book"); dataSource.setUser("zhao"); dataSource.setPassword("123456"); Connection conn = dataSource.getConnection(); System.out.println(conn); conn.close(); }
手动创建Driver数据源
@Test //手动创建Driver数据源 public void TestOne() throws Exception{ DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/book"); dataSource.setUsername("zhao"); dataSource.setPassword("123456"); Connection conn = dataSource.getConnection(); System.out.println(conn); conn.close(); }
提取数据库信息放到配置文件中读取
上面都是我们手动创建然后配置信息都在java源代码中这样会导致以后如果修改数据库的链接信息不方便
后期更改数据库的要找到源码修改太麻烦
提取jdbc.properties配置文件
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/book jdbc.username=zhao jdbc.password=123456
在设置properties的时候,里面的内容不可以加上分号
读取jdbc.properties配置文件创建连接池
//读取jdbc.properties配置文件创建连接池 @Test public void TestThree() throws Exception { ResourceBundle rb = ResourceBundle.getBundle("jdbc"); // 指定连接的驱动方式 ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass(rb.getString("jdbc.driver")); dataSource.setJdbcUrl(rb.getString("jdbc.url")); dataSource.setUser(rb.getString("jdbc.username")); dataSource.setPassword(rb.getString("jdbc.password")); Connection conn = dataSource.getConnection(); System.out.println(conn); }
上面都不是Spring的 容器来配置数据源的
下面我们使用spring容器创建数据源
Spring配置数据源
可以将DataSource的创建权交由Spring容器去完成
DataSource有无参构造方法,而Spring默认就是通过无参构造方法实例化对象的
DataSource要想使用需要通过set方法设置数据库连接信息,而Spring可以通过set方法进行字符串注入
applicationContext.xml
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/> <property name="user" value="root"/> <property name="password" value="root"/> </bean>
测试从容器当中获取数据源
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); DataSource dataSource = (DataSource) applicationContext.getBean("dataSource"); Connection connection = dataSource.getConnection(); System.out.println(connection);
上面的方法是没有抽取jdbc的配置文件,我们将配置文件抽取到properties文件中
将数据源的配置抽取到properties中,抽取到xml解析比较费劲,properties是键值对的方式,
Spring容器提取配置文件到Properties中然后
抽取jdbc配置文件
applicationContext.xml加载jdbc.properties配置文件获得连接信息。
首先,需要引入context命名空间和约束路径:
命名空间首先要在applicaltionContext.xml中创建
需要引入context命名空间和约束路径: 命名空间:xmlns:context="http://www.springframework.org/schema/context" 约束路径:http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
命名空间的创建在beans中的xmlns中复制第一个的xmlns人然后改成xmlns:context
applicationContext.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" 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"> <context:property-placeholder location="classpath:jdbc.properties"/> <!--加载jdbc的配置文件--> <!-- <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 这里是使用cp30--> <bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource"><!--这是使用druid数据源连接--> <property name="driverClassName" value="${jdbc.driver}"/> <!--这里指定的name值是你的读取jdbc.properties配置文件方法中的set后面的内容--> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> </beans>
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/book jdbc.username=zhao jdbc.password=123456
Spring容器加载properties文件
<context:property-placeholder location="classpath:xx.properties"/> <property name="" value="${key}"/
实现:
//Spring容器创建Druid的数据源 @Test public void TestFive() throws SQLException { ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); DataSource bean = app.getBean(DataSource.class); Connection connection = bean.getConnection(); System.out.println(connection); }
Spring注解开发
spring的注解分为原始注解和新注解
Spring原始注解:
Spring是轻代码重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替Xml配置文件可以简化配置,提高开发效率
Spring原始注解主要是替代的配置
注解 | 说明 |
@Component | 使用在类上用于实例化Bean |
@Controller | 使用在web层类上用于实例化Bean |
@Service | 使用在Service层类上用于实例化Bean |
@Repository | 使用在dao层类上用于实例化Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用用于根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行注入 |
@Value | 注入普通属性 |
@Scope | 标注Bean的作用范围 |
@PostConstruct | 使用在方法上标注该方法是Bean的初始化方法 |
@PreDestroy | 使用在方法上标注该方法是Bean的销毁方法 |
注意:
使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要
进行扫描以便识别使用注解配置的类、字段和方法。
首先我们对比下Spring的依赖注入使用注解和不使用注解的方法
Spring的依赖注入
在创建完UserServiceImpl.java和UserDaoImpl.java之后我们要在配置文件applicationContext.xml中进行对应的Bean对象的创建和注入
UserDaoImpl.java
public class UserDaoImpl implements UserDao { public void save() { System.out.println("come on Running...."); } }
UserServiceImpl.java
public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void save() { userDao.save(); } }
applicationContext.xml
<bean id="userDao" class="com.spring.Dao.Impl.UserDaoImpl"></bean> <!--创建UserDaoImpl的Bean对象--> <bean id="userService" class="com.spring.service.Impl.UserServiceImpl"><!--创建UserServiceImpl的Bean对象--> <property name="userDao" ref="userDao"/><!--将UserDaoImpl的bean对象注入到UserService中--> </bean>
这样配置起来是很麻烦的
Spring的注解注入
我们可以将Spring的要在applicationContext.xml中配置的内容全部都通过注解来解决
@Component 实例化bean对象
UserDaoImpl.java
@Component("userDao") //实例化bean对象,并且这个bean对象的id是userDao // 相当于在applicationContext.xml中配置这个<bean id="userDao" class="com.spring.Dao.Impl.UserDaoImpl"></bean> <!--创建UserDaoImpl的Bean对象--> public class UserDaoImpl implements UserDao { public void save() { System.out.println("come on Running...."); } }
userServiceImpl.java
@Component("userService") // 实例化Bean对象,这个bean对象的id是userService public class UserServiceImpl implements UserService { @Autowired // 类型注入 将这个参数注入到此处 @Qualifier("userDao") // 依赖注入,注入userDao这个bean这个是写你的要注入你的bean的id 你要注入userDaoImpl的bean 它的id是userDao private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void save() { userDao.save(); } }
如果只配置了上面的注解,没有声明注解的作用的范围也是不可以使用的
Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@23ab930d: startup date [Tue Dec 15 15:42:08 CST 2020]; root of context hierarchy
十二月 15, 2020 3:42:08 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
上面的报错就是未配置注解扫描
配置注解扫描要在applicationContext.xml中配置
<!-- 配置注解扫描--> <context:component-scan base-package="com.spring"></context:component-scan>
所以我们在applicationContext.xml的配置文件中设置这个 所以即使不在我们也要创建一个配置文件
因为我们在运行的时候也会通过这个配置文件运行的
public static void main(String[] args) { ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService bean = app.getBean(UserService.class); bean.save(); }
使用@Component或@Repository标识UserDaoImpl需要Spring进行实例化。
//@Component("userDao") //实例化bean对象,并且这个bean对象的id是userDao @Repository("userDao") // 使用作用的dao上的bean实例化注解 // 相当于在applicationContext.xml中配置这个<bean id="userDao" class="com.spring.Dao.Impl.UserDaoImpl"></bean> <!--创建UserDaoImpl的Bean对象--> public class UserDaoImpl implements UserDao { public void save() { System.out.println("come on Running...."); } }
其实我们在使用注解的@Component @Repository @Service @ Controller 这些注解作用都一样只不过是作用在不同的区域更规范,如果不规范也是可以互相使用的
Bean的依赖注入
如果我们要进行bena的依赖注入 可以使用
使用@Autowired或者@Autowired+@Qulifier或者@Resource进行userDao的注入
@Repository("userService") public class UserServiceImpl implements UserService { // @Autowired // 类型注入 将这个参数注入到此处 // @Qualifier("userDao") // 依赖注入,注入userDao这个bean这个是写你的要注入你的bean的id 你要注入userDaoImpl的bean 它的id是userDao @Resource(name = "userDao") private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void save() { userDao.save(); } }
使用@Value进行字符串的注入
@Value("laowang") // value进行普通赋值 private String name;
使用@Scope标注Bean的范围
//@Scope("prototype") @Scope("singleton") public class UserDaoImpl implements UserDao { //此处省略代码 }
使用@PostConstruct标注初始化方法,使用@PreDestroy标注销毁方法
@PostConstruct public void init(){ System.out.println("初始化方法...."); } @PreDestroy public void destroy(){ System.out.println("销毁方法....."); }
Spring新注解
使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
非自定义的Bean的配置:
加载properties文件的配置:context:property-placeholder
组件扫描的配置:context:component-scan
引入其他文件:
注解 | 说明 |
@Configuration | 用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解 |
@ComponentScan |
用于指定 Spring 在初始化容器时要扫描的包。 作用和在 Spring 的 xml 配置文件中 |
@Bean | 使用在方法上,标注将该方法的返回值存储到 Spring 容器中 |
@PropertySource | 用于加载.properties 文件中的配置 |
@Import | 用于导入其他配置类 |
@Configuration 指定当前类是spring的核心配置文件
@ ComponentScan("组件的名称") // 组件扫描
@Bean("dataSource") // Spring会将当前方法的返回值以指定名称存储到Spring容器中
@Import({类})
@Configuration //指定当前类是spring的核心配置文件 @ComponentScan("com.spring") // 组件扫描 相当于 <context:component-scan base-package="com.spring"></context:component-scan> @PropertySource("classpath:jdbc.properties") // 加载配置文件 <context:property-placeholder location="classpath:jdbc.properties"/> public class SpringConfiguration { @Bean("dataSource") // Spring会将当前方法的返回值以指定名称存储到Spring容器中 public DataSource getDataSource() throws PropertyVetoException { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/book"); dataSource.setUser("zhao"); dataSource.setPassword("123456"); return dataSource; } }
eg:
spring的核心配置类
SpringConfiguration.java
@Configuration //指定当前类是spring的核心配置文件 @ComponentScan("com.spring") // 组件扫描 相当于 <context:component-scan base-package="com.spring"></context:component-scan> @Import(DataSourceConfiguration.class) // 将DataourceConfigureation类加载到当前类中 public class SpringConfiguration { }
DataSourceConfiguration.java
@PropertySource("classpath:jdbc.properties") // 加载配置文件 <context:property-placeholder location="classpath:jdbc.properties"/> public class DataSourceConfiguration { // @value进行字符串值的注入 对配置文件的值进行赋值 @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将此方法放到speing容器后后面可以直接使用getBean然后获取方法名 @Bean("dSource") // Spring会将当前方法的返回值以指定名称存储到Spring容器中 public DataSource getDataSource() throws PropertyVetoException { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass(driver); dataSource.setJdbcUrl(url); dataSource.setUser(username); dataSource.setPassword(password); return dataSource; } }
main
public static void main(String[] args) throws SQLException { // ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class); //获取核心配置类 UserService bean = app.getBean(UserService.class); bean.save(); DataSource dataSource = (DataSource) app.getBean("dSource"); // 获取@Bean注解生成的spring容器内的方法 Connection connection = dataSource.getConnection(); System.out.println(connection); }
上面使用这种新注解的方式就彻底放弃了xml配置文件了
Spring整合Junit
1 原始Junit测试Spring的问题
在测试类中,每个测试方法都有以下两行代
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); IAccountService as = ac.getBean("accountService",IAccountService.class);
这两行代码的作用是获取容器,如果不写的话,直接会提示空指针异常。所以又不能轻易删掉。
上述问题解决思路
让SpringJunit负责创建Spring容器,但是需要将配置文件的名称告诉它
将需要进行测试Bean直接在测试类中进行注入
Spring集成Junit步骤
①导入spring集成Junit的坐标
②使用@Runwith注解替换原来的运行期
③使用@ContextConfiguration指定配置文件或配置类
④使用@Autowired注入需要测试的对象
⑤创建测试方法进行测试
Spring集成Junit代码实现
1: ①导入spring集成Junit的坐标
<!--此处需要注意的是,spring5 及以上版本要求 junit 的版本必须是 4.12 及以上--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
②使用@Runwith注解替换原来的运行期
使用@Runwith注解替换原来的运行期
@RunWith(SpringJUnit4ClassRunner.class) // 测试 //@ContextConfiguration("classpath:applicationContext.xml") //告诉它测试的文件是哪个 @ContextConfiguration(classes = {SpringConfiguration.class}) // 测试核心配置类 public class springTest { @Autowired // 注入要测试的 对象 private UserService userService; @Test public void save(){ userService.save(); } }
③使用@ContextConfiguration指定配置文件或配置类
@RunWith(SpringJUnit4ClassRunner.class) // 测试 //@ContextConfiguration("classpath:applicationContext.xml") //加载spring核心配置文件 @ContextConfiguration(classes = {SpringConfiguration.class}) // 加载测试核心配置类 public class springTest { @Autowired // 注入要测试的 对象 private UserService userService; @Test public void save(){ userService.save(); } }
④使用@Autowired注入需要测试的对象
@Autowired // 注入要测试的 对象 private UserService userService;
⑤创建测试方法进行测试
@Test public void save(){ userService.save(); }