Spring —— 数据源配置和注解开发
一、前言
在熟悉 了Spring的配置文件后,我们尝试用Spring配置数据源。由于涉及了数据源的配置,我们需要导入几个数据库连接池的maven坐标:
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.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.1.10</version></dependency>
并且需要用Junit的单元测试:
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version><scope>test</scope><dependency>
当然还需要Spring框架:
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.9.RELEASE</version></dependency>
二、配置数据源
1.准备
首先我们依旧准备一下Dao层和service层的接口和实现类:
dao层:
public interface UserDao {public void save();
}
public class UserDaoImpl implements UserDao {@Overridepublic void save() {System.out.println("save running...");}
}
service层:
public interface UserService {public void save();
}
public class UserServiceImpl implements UserService {private String driver;private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}@Overridepublic void save() {System.out.println(driver);userDao.save();}}
准备好后,我们通过依赖注入,将UserDao和UserService注入到容器中
<bean id="userDao" class="com.yds.dao.impl.UserDaoImpl"></bean><bean id="userService" class="com.yds.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"></property>
</bean>
2.测试(无配置文件)
现在我们再创建一个测试类,用于测试数据库是否连接:
步骤依旧和JDBC的步骤一样:
1.注册驱动 2.获取连接
我们先测试c3p0的:
@Test//测试手动创建c3p0数据源public void test1() throws PropertyVetoException, SQLException {ComboPooledDataSource dataSource = new ComboPooledDataSource();dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");dataSource.setUser("root");dataSource.setPassword("123456");Connection connection = dataSource.getConnection();System.out.println(connection);connection.close();
可以看到这里我们就已经获取了连接对象的地址了(表示连接成功):
同理druid也是一样的:
@Test//测试手动创建druid数据源public void test2() throws SQLException {DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/test");dataSource.setUsername("root");dataSource.setPassword("123456");DruidPooledConnection connection = dataSource.getConnection();System.out.println(connection);connection.close();
3.测试(有配置文件)
首先我们先创建一个.properties文件,用于配置JDBC的字符串(例如:驱动、url等)
jdbc.driver = com.mysql.cj.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/test
jdbc.username = root
jdbc.password = 123456
我们把这个文件命名为jdbc.properties。
然后我们通过ResourceBundle rb = ResourceBundle.getBundle("jdbc");来读取配置文件,来替换之前的死字符串:
@Test//测试手动创建druid数据源(加载配置文件(解耦))public void test3() throws PropertyVetoException, SQLException {//读取配置文件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");DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName(driver);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);DruidPooledConnection connection = dataSource.getConnection();System.out.println(connection);connection.close();
效果如下,和之前一样:
4.测试(Spring)
刚刚的测试是都没有用到Spring框架的,耦合性很高,下面我们将使用Spring来达到刚刚的效果。
首先先在Spring中导入外部的properties文件,然后我们使用Spring表达式来将properties的内容注入到容器中,最后通过组件扫描,来让配置文件被扫描到,从而执行Spring表达式。
<!-- 加载外部的properties文件--><context:property-placeholder location="classpath:jdbc.properties"/><!-- 使用spring表达式--><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driver}"></property><property name="jdbcUrl" value="${jdbc.url}"></property><property name="user" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 配置组件扫描--><context:component-scan base-package="com.yds"/>
现在我们需要一个测试类,用Spring框架运行:
@Test//测试Spring容器产生c3p0数据源对象(druid步骤相同)public void test4() throws SQLException {ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");//通过查找getDataSource的方法的name,来直接获取这个beanComboPooledDataSource dataSource = (ComboPooledDataSource) app.getBean("dataSource");Connection connection = dataSource.getConnection();System.out.println(connection);connection.close();}
效果如下:
三、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的销毁方法
新注解:
注解 说明 @Configuration 用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解 @ComponentScan 用于指定 Spring 在初始化容器时要扫描的包。作用和在 Spring 的 xml 配置文件中的<context:component-scan base-package="com.itheima"/>一样@Bean 使用在方法上,标注将该方法的返回值存储到 Spring 容器中 @PropertySource 用于加载.properties 文件中的配置 @Import 用于导入其他配置类
导入注解坐标:
<dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.2</version></dependency>
于是我们就可以用注解重写dao层的实现类:
//<bean id="userDao" class="com.yds.dao.impl.UserDaoImpl"></bean>//@Component("userDao")
//用下面的注解替代,表示dao层的组件
@Repository("userDao")
public class UserDaoImpl implements UserDao {@Overridepublic void save() {System.out.println("save running...");}
}
同样service层的实现类我们也可以用注解替代:
//<bean id="userService" class="com.yds.service.impl.UserServiceImpl">//@Component("userService")
//用下面的注解替代,表示Service层的注解
@Service("userService")//这里可以设置Bean是单例还是多例的
//@Scope("prototype")
@Scope("singleton")
public class UserServiceImpl implements UserService {//注入@Value("${jdbc.driver}")private String driver;//使用注解注入userDao,注意:注解注入可以不用写setter//<property name="userDao" ref="userDao"></property>//@Autowired//@Qualifier("userDao")//是按照id值从容器中进行匹配的 但是注意此处需要和@Autowired一起使用//可以替代为@Resource(name="userDao")//相当于@Autowired + @Qualifier,按照名称进行注入private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}@Overridepublic void save() {System.out.println(driver);userDao.save();}@PostConstructpublic void init(){System.out.println("init");}@PreDestroypublic void destroy(){System.out.println("destroy");}
}
然后我们就可以把数据库的注解配置放在一个类中:
我们这里也同样导入了properties文件,最终返回一个dataSource对象,这个对象经过依赖注入的处理,已经可以进行连接了。
//<context:property-placeholder location="classpath:jdbc.properties"/>
@PropertySource("classpath:jdbc.properties")
//配置数据源配置
public class DataSourceConfiguration {@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") //Spring会将当前方法的返回值以指定名称存储到Springpublic DataSource getDataSource() throws PropertyVetoException, SQLException {ComboPooledDataSource dataSource = new ComboPooledDataSource();dataSource.setDriverClass(driver);dataSource.setJdbcUrl(url);dataSource.setUser(username);dataSource.setPassword(password);return dataSource;}
}
同时,我们需要一个主配置文件将我们所有的配置导入整合,最终只需要调用核心配置就可以配置成功了:
//标志该类是Spring的核心(主)配置文件
@Configuration
//<context:component-scan base-package="com.yds"/>
@ComponentScan("com.yds")
@Import({DataSourceConfiguration.class})
public class SpringConfiguration {}
最后我们写出一个测试类,来测试是否连接成功:
public class UserController {public static void main(String[] args) {//记得配置组件扫描//ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class);
// ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = app.getBean(UserService.class);userService.save();
// app.close();}
}
四、集成Junit
首先导入坐标:
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.1.9.RELEASE</version></dependency>
我们用注解来测试一下我们获取的dataSource
@RunWith(SpringJUnit4ClassRunner.class)//配置文件
//@ContextConfiguration("classpath:applicationContext.xml")//全注解
@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {@Autowiredprivate UserService userService;@Autowiredprivate DataSource dataSource;@Testpublic void test1() throws SQLException {userService.save();System.out.println(dataSource.getConnection());}}
效果如下: