IoC和DI注解开发
一、数据源(连接池)的作用
- 提高程序性能
- 事先实例化数据源,初始化部分连接资源
- 使用连接资源时从数据源中获取
- 使用完毕后归还资源
常见的数据源(连接池):DBCP、C3P0、BoneCP、Druid等
- 数据源开发步骤
- 导入数据源的坐标和数据库驱动坐标
- 创建数据源对象
- 设置数据源的基本连接数据
- 使用数据源获取连接资源和归还连接资源
- 数据源的手动创建
- 导入坐标(这里采用C3P0和Druid)
- 导入MySQL驱动坐标
<dependencies> <!--C3P0连接池--> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.1</version> </dependency> <!--druid连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.9</version> </dependency> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.37</version> </dependency> <!--junit测试使用--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
- 创建连接池
- 创建C3P0
public class DataSourceTest { @Test public void testC3P0() throws PropertyVetoException, SQLException { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); dataSource.setUser("root"); dataSource.setPassword("root"); Connection connection = dataSource.getConnection(); System.out.println(connection); } }
- 创建Druid
@Test public void testDruid() throws SQLException { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/test"); dataSource.setUsername("root"); dataSource.setPassword("root"); Connection connection = dataSource.getConnection(); System.out.println(connection); }
- 提取jdbc.properties配置文件
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test jdbc.username=root jdbc.password=root
- 读取jdbc.properties配置文件创建连接池
- 创建Druid
@Test public void testDruidbyJdbcProperties() throws SQLException { ResourceBundle resourceBundle = ResourceBundle.getBundle("jdbc"); DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(resourceBundle.getString("driver")); dataSource.setUrl(resourceBundle.getString("url")); dataSource.setUsername(resourceBundle.getString("username")); dataSource.setPassword(resourceBundle.getString("password")); Connection connection = dataSource.getConnection(); System.out.println(connection); }
- 创建C3P0
@Test public void testC3P0byJdbcProperties() throws PropertyVetoException, SQLException { ResourceBundle resourceBundle = ResourceBundle.getBundle("jdbc"); ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass(resourceBundle.getString("jdbc.driver")); dataSource.setJdbcUrl(resourceBundle.getString("jdbc.url")); dataSource.setUser(resourceBundle.getString("jdbc.username")); dataSource.setPassword("jdbc.password"); Connection connection = dataSource.getConnection(); System.out.println(connection); }
- Spring配置数据源
将DataSource的创建权交给Spring容器
- DataSource有无参构造
- 通过set设置数据库连接信息
<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配置文件
- 引入context命名空间和约束地址
- 命名空间:
xmlns:context="http://www.springframework.org/schema/context"
- 约束地址:
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
- 抽取配置文件
<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>
- 引入context命名空间和约束地址
二、注解开发
1. Spring原始注解
Spring是轻量级的框架,但繁重的配置影响开发效率,所以注解开发是必然趋势,通过注解开发替代xml配置文件,提高开发效率。
- Spirng的原始注解
@Component 使用在类上实例化Bean
@Controller 使用在web层上实例化Bean
@Service 使用在service层上实例化Bean
@Repository 使用在dao层上实例化Bean
@Autowired 使用在字段上根据类型依赖注入
@Qualifier 使用结合@Autowired一起用于根据名称进行注入
@Resource 相当于前面两个按照名称注入
@Value 注入普通属性
@Scope 标注Bean的作用范围
@PostConstruct 使用在方法上标注该方法为初始化方法
@PreDestroy 使用在方法上标注该方法为Bean的销毁方法 - 使用注解开发时,要在applicationContext.xml配置扫描
<context:component-scan base-package="xyz.nchu200462"></context:component-scan>
- 各个注解的使用方式
- @Component 使用在类上实例化Bean
//语义化较差
@Component("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("save running...");
}
}
- @Controller 使用在web层上实例化Bean
- @Service 使用在service层上实例化Bean
@Service("userService")
public class UserServiceImpl implements UserService {
//<property name="userDao" ref="userDao"></property>
@Autowired
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
- @Repository 使用在dao层上实例化Bean
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("save running...");
}
}
- @Autowired 使用在字段上根据类型依赖注入
//通过Spring对类型进行匹配
@Autowired
private UserDao userDao;
- @Qualifier 使用结合@Autowired一起用于根据名称进行注入
@Autowired
@Qualifier("userDao")
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
- @Resource 相当于前面两个按照名称注入
@Resource(name = "userDao")
private UserDao userDao;
- @Value 注入普通属性
@Value("注入普通数据")
private String str;
@Value("${driver}")
private String driver;
- @Scope 标注Bean的注入范围
@Scope("singleton")
@Service("userService")
public class UserServiceImpl implements UserService {
//<property name="userDao" ref="userDao"></property>
@Resource(name = "userDao")
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
- @PostConstruct 使用在方法上标注该方法为初始化方法
- @PreDestroy 使用在方法上标注该方法为Bean的销毁方法
@PostConstruct
public void init(){
System.out.println("init");
}
@PreDestroy
public void destroy(){
System.out.println("destroy");
}
- Spring新注解
@Configuration 用于指定当前类是一个Spring配置类,当创建容器的时候会从该类上加载注解
@ConponentScan 用于指定Spring在初始化容器时要扫描的包。作用和Spring的xml配置中的<context:component-scan base-package=“xyz.nchu200462” />一样
@Bean 使用在方法上,标注将该方法的返回值存储在Spring容器中
@PropertySource 用于加载.properties文件中的配置
@Import 用于导入其他配置类 - 各个注解的详细使用
- @Configuration 用于指定当前类是一个Spring配置类,当创建容器的时候会从该类上加载注解
//标志该类是Spring的一个核心配置类
@Configuration
//只能有一个核心配置类
- @ConponentScan 用于指定Spring在初始化容器时要扫描的包。作用和Spring的xml配置中的<context:component-scan base-package="xyz.nchu200462" />一样
@ComponentScan("xyz.nchu200462")
- @Bean 使用在方法上,标注将该方法的返回值存储在Spring容器中
@Bean("dataSource")
public DataSource getDataSource() throws PropertyVetoException, SQLException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
return dataSource;
}
- @PropertySource 用于加载.properties文件中的配置
@PropertySource("classpath:jdbc.properties")
- @Import 用于导入其他配置类
@Import({DataSourceConfiguration.class})
三、Spring集成Junit
由于在测试类中,都有从Spring配置文件中获取容器的代码,比较麻烦。所以考虑不用这些代码的方法。
解决思路:
- 让SpringJunit负责创建Spring容器,但是需要将配置文件的信息告诉它
- 将需要进行测试的Bean直接在测试类中进行注入
Spring集成Junit的步骤
- 导入Spring继承Junit的坐标
- 使用@Runwith注解替换原来的运行期
- 使用@ContextConfiguration指定配置文件或配置类
- 使用@Autowired注入需要测试的对象
- 创建测试方法进行测试
- 导入Spring继承Junit的坐标
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
<scope>test</scope>
</dependency>
- 使用@Runwith注解替换原来的运行期
@RunWith(SpringJUnit4ClassRunner.class)
- 使用@ContextConfiguration指定配置文件或配置类
@ContextConfiguration(classes = {SpringConfiguration.class})
- 使用@Autowired注入需要测试的对象
@Autowired
private UserServiceImpl userService;
- 创建测试方法进行测试
@Test
public void testUserService(){
userService.save();
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {
@Autowired
private UserServiceImpl userService;
@Test
public void testUserService(){
userService.save();
}
}