Spring学习之路 第二篇
- 在前一篇的入门基础上,我们继续学习Spring。
- 本文涉及以下内容:
1. 基于注解的IOC配置。
2. 基于XML的IOC案例。
3. 基于注解的IOC案例。
4. 新注解说明(纯注解配置)。
5. Spring整合Junit。
1. 基于注解的IOC配置 |
1.1 使用@Component 注解配置管理的资源
Component:
- 相当于:< bean id="" class="">
- 作用:用于把当前类对象存入Spring容器中
- 属性:
- value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改成小写。
- 使用注解开发时,需要知道扫描哪些包的注解,修改bean.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"> <!--告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,而是 context名称空间和约束中--> <context:component-scan base-package="fang"></context:component-scan> </beans>
- 编写需要存入Spring容器中的类:
- Component不写value值,默认id为类名,且首字母小写。
@Component public class AccountServiceImpl implements IAccountService { private IAccountDao accountDao; @Override public void saveAccount() { accountDao.saveAccount(); } }
1.2 由Component注解衍生的注解
- 他们三个注解都是针对一个的衍生注解,他们的作用及属性都是一模一样的。他们只不过是提供了更加明确的语义化。
- @Controller:一般用于表现层的注解。
- @Service:一般用于业务层的注解。
- @Repository:一般用于持久层的注解。
1.3 @Autowired,注入数据
- 他们的作用就和在xml配置文件中的bean标签中写一个< property>标签的作用是一样的
作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功。若有多个时,会有问题。@Service("accountService") public class AccountServiceImpl implements IAccountService { @Autowired private IAccountDao accountDao; @Override public void saveAccount() { accountDao.saveAccount(); } }
1.4 @Autowired,按照Bean的id注入
- 在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。它在给字段注入时不能独立使用,必须和@Autowired 一起使用;但是给方法参数注入时,可以独立使用。
- 属性 value:指定 bean 的 id。
@Service("accountService") public class AccountServiceImpl implements IAccountService { @Autowired @Qualifier("accountDao") private IAccountDao accountDao; @Override public void saveAccount() { accountDao.saveAccount(); } }
1.5 @Resource,直接按照 Bean 的 id 注入
- 可以替换@Autowired和@Qualifier
作用:直接按照 Bean 的 id 注入。它也只能注入其他 bean 类型。
属性: name:指定 bean 的 id。 - 若在使用@Resource注解的时候,发现相应的包,这是JDK版本的问题,解决办法。在pom.xml中添加如下包:
<dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.2</version> </dependency>
- 使用Resource注解如下:
@Service("accountService") public class AccountServiceImpl implements IAccountService { @Resource(name = "accountDao") private IAccountDao accountDao; @Override public void saveAccount() { accountDao.saveAccount(); } }
1.5 @Value,注入基本数据类型和 String 类型数据的
- 注意:@Autowired、@Qualifier、@Resource这三个注解只能注入其他的bean类型数据。而基本类型和String类型使用不了。需使用@Value注解。
- 属性: value:用于指定值
- 用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)SpEL的写法:${表达式}
1.5 @Scope,用于改变作用范围的。
作用:指定bean的作用范围。
属性:value:指定范围的值。
- 取值:singleton prototype request session globalsession
- 不写这个注解默认是singleton。
@Service("accountService") @Scope("prototype") public class AccountServiceImpl implements IAccountService { @Resource(name = "accountDao") private IAccountDao accountDao; @Override public void saveAccount() { accountDao.saveAccount(); } }
1.5 和生命周期相关的:(了解)
- 相当于:< bean id="" class="" init-method="" destroy-method="" />
- @PostConstruct:用于指定初始化方法。
- @PreDestroy:用于指定销毁方法。
2. 基于XML的IOC案例 |
知识点:dbutils,c3p0连接池。
2.1 导包,编辑pom.xml
<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.10</version>
</dependency>
</dependencies>
2.2 编写配置文件bean.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="accountService" class="fang.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<bean id="accountDao" class="fang.dao.impl.AccountDaoImpl">
<property name="runner" ref="runner"/>
</bean> <!--增加scope="prototype"不是单例对象了-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源-->
<constructor-arg name="ds" ref="dataSource"/>
</bean>
<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/eesy"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
</beans>
2.3 编写Account类,省略get、set等方法
public class Account implements Serializable {
private Integer id;
private String name;
private Float money;
...
}
2.3 编写持久层接口和实现类
IAccountDao接口:
public interface IAccountDao {
List<Account> findAllAccount();
Account findAccountById(Integer accountId);
void saveAccount(Account account);
void updateAccount(Account account);
void deleteAccount(Integer accountId);
}
AccountDaoImpl实现类:
public class AccountDaoImpl implements IAccountDao {
private QueryRunner runner;
public void setRunner(QueryRunner runner) {
this.runner = runner;
}
@Override
public List<Account> findAllAccount() {
try {
return runner.query("select * from account", new BeanListHandler<Account>(Account.class));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public Account findAccountById(Integer accountId) {
try {
return runner.query("select * from account where id = ?", new BeanHandler<Account>(Account.class), accountId);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void saveAccount(Account account) {
try {
runner.update("insert into account(name,money) values(?,?)", account.getName(), account.getMoney());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void updateAccount(Account account) {
try {
runner.update("update account set name=?,money=? where id=?", account.getName(), account.getMoney(),account.getId());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void deleteAccount(Integer accountId) {
try {
runner.update("delete from account where id=?" ,accountId);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
2.4 编写业务层接口和实现类
业务层接口IAccountService:
public interface IAccountService {
List<Account> findAllAccount();
Account findAccountById(Integer accountId);
void saveAccount(Account account);
void updateAccount(Account account);
void deleteAccount(Integer accountId);
}
业务层实现类AccountServiceImpl:
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public List<Account> findAllAccount() {
return accountDao.findAllAccount();
}
@Override
public Account findAccountById(Integer accountId) {
return accountDao.findAccountById(accountId);
}
@Override
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
@Override
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
@Override
public void deleteAccount(Integer accountId) {
accountDao.deleteAccount(accountId);
}
}
2.5 编写测试类AccountServiceTest:
public class AccountServiceTest {
@Test
public void testFindAll() {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService as = ac.getBean("accountService", IAccountService.class);
List<Account> accounts = as.findAllAccount();
for (Account account : accounts) {
System.out.println(account);
}
}
@Test
public void testFindOne() {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService as = ac.getBean("accountService", IAccountService.class);
Account account = as.findAccountById(1);
System.out.println(account);
}
@Test
public void testSave() {
Account account = new Account();
account.setName("fang");
account.setMoney(12345F);
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService as = ac.getBean("accountService", IAccountService.class);
as.saveAccount(account);
}
@Test
public void testUpdate() {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService as = ac.getBean("accountService", IAccountService.class);
Account account = as.findAccountById(5);
account.setMoney(10000F);
as.updateAccount(account);
}
@Test
public void testDelete() {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService as = ac.getBean("accountService", IAccountService.class);
as.deleteAccount(5);
}
}
3. 基于注解的IOC案例 |
前提:基于注解的IOC案例和基于XML的IOC案例几乎一样。
3.1 配置文件bean.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">
<!-- 告知spring在创建容器时要扫描的包 -->
<context:component-scan base-package="fang"/>
<!--配置QueryRunner-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源-->
<constructor-arg name="ds" ref="dataSource"/>
</bean>
<!-- 配置数据源 -->
<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/eesy"/>
<property name="user" value="root"/>
<property name="password" value="1234"/>
</bean>
3.2 持久层的实现类AccountDaoImpl:
@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao {
@Autowired
private QueryRunner runner;
...
}
3.3 业务层的实现类AccountServiceImpl:
@Service("accountService")
public class AccountServiceImpl implements IAccountService{
@Autowired
private IAccountDao accountDao;
...
}
4. 新注解说明(纯注解配置) |
@Configuration:
- 作用:指定当前类是一个配置类
- 细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。
@ComponentScan:
- 作用:用于通过注解指定spring在创建容器时要扫描的包
- value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。
@Bean:
- 作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中
- name:用于指定bean的id。当不写时,默认值是当前方法的名称
- 细节:当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。查找的方式和Autowired注解的作用是一样的。
@Import:
- 作用:用于导入其他的配置类
- value:用于指定其他配置类的字节码。
- 当我们使用Import的注解之后,有Import注解的类就父配置类,而导入的都是子配置类.
@PropertySource:
- 作用:用于指定properties文件的位置
- value:指定文件的名称和路径。关键字:classpath,表示类路径下
@Qualifier:
- 在参数上面用法如下。
4.1 编辑主配置类SpringConfiguration和副配置类JdbcConfig。
- SpringConfiguration(java/fang/config/SpringConfiguration.java):
- @Configuration不写是因为在测试类中加载了SpringConfiguration.class的
//@Configuration @ComponentScan("fang") @Import(jdbcConfig.class) @PropertySource("classpath:jdbcConfig.properties") public class SpringConfiguration { }
-
JdbcConfig(java/fang/config/JdbcConfig.java):
public class JdbcConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; /** * 用于创建一个QueryRunner对象 * @param dataSource * @return */ @Bean(name="runner") @Scope("prototype") public QueryRunner createQueryRunner(@Qualifier("ds2") DataSource dataSource){ return new QueryRunner(dataSource); } /** * 创建数据源对象 * @return */ @Bean(name="ds2") 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); } } @Bean(name="ds1") public DataSource createDataSource1(){ try { ComboPooledDataSource ds = new ComboPooledDataSource(); ds.setDriverClass(driver); ds.setJdbcUrl("jdbc:mysql://localhost:3306/eesy02"); ds.setUser(username); ds.setPassword(password); return ds; }catch (Exception e){ throw new RuntimeException(e); } } }
- 测试类:
- 若在AnnotationConfigApplicationContext也加入了JdbcConfig.class,那么 注解@Import(jdbcConfig.class)可不写。
@Test public void testFindAll() { ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class); IAccountService as = ac.getBean("accountService", IAccountService.class); List<Account> accounts = as.findAllAccount(); for (Account account : accounts) { System.out.println(account); } }
5. Spring整合Junit |
Spring整合junit的配置:
- 导入整合junit的jar包(坐标)
- 使用Junit提供的一个注解把原有的main方法替换,替换成spring提供的
- @Runwith
- 告知spring的运行器,spring何让io创建是基于xml还是注解的,并且说明位置
- @ContextConfiguration
- locations:指定xml文件的位置,加上classpath关键字,表示在类路径下
- classes:指定注解类所在位置
- @ContextConfiguration
- 当我们使用spring 5.x版本时,要求junit的jar包必须是4.12及以上。
-
在pom.xml中导入整合junit的jar包(坐标),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> </dependency>
-
编辑测试类(基于注解的或xml的):
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfiguration.class) //基于注解的 //@ContextConfiguration(locations = "classpath:bean.xml") 基于xml的 public class AccountServiceTest { @Autowired private IAccountService as; @Test public void testFindAll() { //ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class); //IAccountService as = ac.getBean("accountService", IAccountService.class); List<Account> accounts = as.findAllAccount(); for (Account account : accounts) { System.out.println(account); } }
- 到这里第二阶段的学习就结束啦。