Spring框架第二天
1、使用注解完成IOC
(注意:这个是 注解 + XML 配置的,并没有完全摆脱XML)
首先,修改配置文件约束,这是用注解配置IOC时的约束,类似于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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
然后告知Spring在创建容器时要扫描的包,这时Spring才能知道是注解配置的项目
<context:component-scan base-package="com.cjf"></context:component-scan>
@Component 该注解的作用:
<bean id="accountService"class="com.cjf.service.impl.AccountServiceImpl">
</bean>
@Component("accountService")
public class AccountServiceImpl implements IAccountService {
}
@Controller:表现层
@Service:业务层
@Repository:持久层
@Autowired 该注解的作用:直接按照数据类型IAccountDao匹配实现类AccountDaoImpl,
如果存在多个实现类,则按照名字匹配,如果名字也不一样,就报错
(可以去掉set方法了)
<bean id="accountService2" class="com.cjf.service.impl.AccountServiceImpl2">
<property name="birthday" ref="date"></property>
</bean>
<bean id="date" class="java.util.Date"></bean>
@Autowired
private IAccountDao accountDao;//三个都只能注入Bean类型
@Autowired
@Qualifier("accountDao1")//配合使用
@Resource(name="accountDao1")//直接使用
@Scope 该注解的作用:
@Scope("singleton")//单例
@Scope("prototype")//多例
@ 生命周期了解
2、案例IOC(基于XML,持久层使用dbutils技术)
-
导入坐标依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
2、准备:Account实体类
持久层实现类:
public class AccountDaoImpl implements IAccountDao {
private QueryRunner runner;
public void setRunner(QueryRunner runner) { //为了依赖注入
this.runner = runner;
}
public List<Account> findAllAccount() {
try {
return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public Account findAccountById(Integer id) {
try {
return runner.query("select * from account where id= ?",new BeanHandler<Account>(Account.class),id);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void saveAccount(Account account) {
try {
runner.update("insert into account(name,money)values (?,?)",account.getName(),account.getMoney());
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void updateAccount(Account account) {
try {
runner.update("update account set name = ? ,money = ? where id = ?",account.getName(),account.getMoney(),account.getId());
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void deleteAccount(Integer id) {
try {
runner.update("delete from account where id = ?",id);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
业务层实现类:
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
public List<Account> findAllAccount() {
return accountDao.findAllAccount();
}
public Account findAccountById(Integer id) {
return accountDao.findAccountById(id);
}
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
public void deleteAccount(Integer id) {
accountDao.deleteAccount(id);
}
}
配置文件bean.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置Service-->
<bean id="accountService" class="com.cjf.service.impl.AccountServiceImpl">
<!--注入dao-->
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--配置dao对象-->
<bean id="accountDao" class="com.cjf.dao.impl.AccountDaoImpl">
<!--注入QueryRunner-->
<property name="runner" ref="runner"></property>
</bean>
<!--配置QueryRunner对象-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源-->
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<!--配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--连接数据库的必备信息-->
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/eesy"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
</bean>
</beans>
测试方法(模拟表现层)
@Test
public void testFindAll(){
//1、获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.得到业务层对象
IAccountService as = (IAccountService) ac.getBean("accountService");
//3、执行方法
List<Account> accounts = as.findAllAccount();
for(Account account : accounts){
System.out.println(account);
}
}
3、案例IOC(基于注解,持久层使用dbutils技术)
1.配置文件约束使用注解的约束
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--告知Spring在创建容器时要扫描的包,
配置所需要的标签不是在beans的约束中,
而是一个名称为context名称空间和约束中
-->
<context:component-scan base-package="com.cjf"></context:component-scan>
</beans>
2.改造持久层的实现类
将创建javabean的xml改为使用注解@Repository("accountDao")
注入的依赖改为使用注解@Autowired,可以去掉set方法
@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao {
@Autowired
private QueryRunner runner;
public QueryRunner getRunner() {
return runner;
}
public List<Account> findAllAccount() {
try {
return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public Account findAccountById(Integer id) {
try {
return runner.query("select * from account where id= ?",new BeanHandler<Account>(Account.class),id);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void saveAccount(Account account) {
try {
runner.update("insert into account(name,money)values (?,?)",account.getName(),account.getMoney());
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void updateAccount(Account account) {
try {
runner.update("update account set name = ? ,money = ? where id = ?",account.getName(),account.getMoney(),account.getId());
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void deleteAccount(Integer id) {
try {
runner.update("delete from account where id = ?",id);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
3、改造业务层的实现类
将创建javabean的xml改为使用注解
注入的依赖改为使用注解
@Service("accountService")
public class AccountServiceImpl implements IAccountService {
@Autowired
private IAccountDao accountDao;
//有了Autowired就可以去掉set方法
public List<Account> findAllAccount() {
return accountDao.findAllAccount();
}
public Account findAccountById(Integer id) {
return accountDao.findAccountById(id);
}
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
public void deleteAccount(Integer id) {
accountDao.deleteAccount(id);
}
}
4.完全摆脱XML,使用新注解完成纯注解开发
既然是注解替换XML开发,必然要在代码中完成XML文件的替换
所以创建Config包下的SpringConfiguration类
1、使用@Configuration替换XML文件的约束,代表是一个配置文件
2、使用@ComponentScan(basePackages = {"com.cjf"}),代替XML配置
<context:component-scan base-package="com.cjf"></context:component-scan>
3、@Bean
作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中
属性:
name:用于指定bean的id,不写时,默认值是当前方法的名称
细节:
当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。查找的方式和Autowired注解的作用是一样的
@Configuration
@ComponentScan(basePackages = {"com.cjf"})
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.user}")
private String username;
@Value("${jdbc.password}")
private String password;
/*
用于创建一个QueryRunner对象
*/
@Bean(name = "runner")
@Scope("prototype")
public QueryRunner createQueryRunner(DataSource dataSource) {
return new QueryRunner(dataSource);
}
/*
用于创建数据源对象
*/
@Bean(name = "dataSource")
public DataSource createDataSource() {
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
5.改用AnnotationConfigApplicationContext实例化测试类的容器
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class)
6.QueryRunner对象改为多例
/*
用于创建一个QueryRunner对象
*/
@Bean(name = "runner")
@Scope("prototype")
public QueryRunner createQueryRunner(DataSource dataSource) {
return new QueryRunner(dataSource);
}
7.@Configuration可以不写的情况
当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写,参数可以添加多个
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class)
7.@import注解
@import
作用:用于导入其他的配置类
属性:
value:用于指定其他配置类的字节码
@Import("JdbcConfig.class")
当我们使用import的注解之后,有import注解的类就父配置类,而导入的都是子配置类
7.使用jdbcConfig.properties
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/eesy
jdbc.user = root
jdbc.password = 123456
8.@PropertySource
@PropertiesSource
作用:用于指定properties文件的位置
属性:
value:指定文件的名字和路径
关键字:classpath,表示类路径下
@PropertySource("classpath:jdbcConfig.properties")
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.user}")
private String username;
@Value("${jdbc.password}")
private String password;
/*
用于创建数据源对象
*/
@Bean(name = "dataSource")
public DataSource createDataSource() {
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
8.如果使用不同的数据源,即有两个dataSource的情况下,可以使用代码内部添加注解@Qualifier("dataSource")的方式指定想要的数据源
@Bean(name = "runner")
@Scope("prototype")
public QueryRunner createQueryRunner(@Qualifier("dataSource") DataSource dataSource) {
return new QueryRunner(dataSource);
}
9.使用Junit单元测试:测试我们的配置
使用junit单元测试
Spring整合junit的配置:
1、导入spring整合junit的jar坐标(依赖)
2、使用junit提供的一个注解把原有的main方法替换了,替换成Spring的提供的
@Runwith
3、告知Spring的运行器,spring和ioc创建是基于xmL还是注解的,并且说明位置
@ContextConfiguration
location:指定xmL文件的位置,加上classpath关键字,表示在类路径下
classes:指定注解类所在的位置
导入test依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
使用@ContextConfiguration(classes = SpringConfiguration.class)代替
获得容器的语句
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountServiceTest {
@Autowired
private IAccountService as ;
@Test
public void testFindAll(){
//3、执行方法
List<Account> accounts = as.findAllAccount();
for(Account account : accounts){
System.out.println(account);
}
}
@Test
public void testFindOne(){
//3、执行方法
Account account = as.findAccountById(1);
System.out.println(account);
}
@Test
public void testSave(){
//3、执行方法
Account account = new Account();
account.setId(4);
account.setMoney(10000);
account.setName("ddd");
as.saveAccount(account);
System.out.println(account);
}
@Test
public void testUpdate(){
//3、执行方法
Account account = as.findAccountById(1);
account.setName("AAA");
as.updateAccount(account);
}
@Test
public void testDelete(){
//3、执行方法
as.deleteAccount(4);
}
}