文章目录
1.Spring基于注解的IOC
1.1用于创建对象的注解
@Component
:把当前类存入到spring容器中。其属性如下。value
:用于指定当前类的id,默认值是当前类名,且首字母改小写。
@Controller
:将当前表现层对象存入spring容器中。@Service
: 将当前业务层对象存入spring容器中。@Repository
: 将当前持久层对象存入spring容器中。
@Controller,@Service,@Repository
注解的作用和属性与@Component
是一模一样的,可以相互替代,它们的作用是使三层对象的分别更加清晰.
1.2用于注入数据的注解
-
这些注解相当于
bean.xml
中的<property>
标签。 -
@Autowired
注解- 作用:
- 自动按照类型注入
- 注入的过程:
- 1.当spring容器中有且只有一个对象的类型与要注入的类型相同时,注入该对象。
- 2.当spring容器中有多个对象类型与要注入的类型相同时,使用要注入的变量名作为bean的
id
,在spring 容器查找,找到则注入该对象.找不到则报错 。
- 出现位置:
- 可以是成员变量上,也可以是方法上
- 细节:
- 使用注解注入时,set方法可以省略
- 作用:
-
@Qualifier
注解:- 作用:
- 在按照类中注入的基础上再按照名称注入。它在给
类成员注入时不能单独使用
,但是在给方法注入时可以。
- 在按照类中注入的基础上再按照名称注入。它在给
- 属性:
value
:用于指定bean的id
- 作用:
-
@Resource
注解:- 作用:
- 直接按照bean的id注入。它可以独立使用 (可以看作上面两种注解的综合)
- 属性:
- name:用于指定bean的id
- 作用:
以上三个注入都只能注入其他bean类型的数据,而
基本类型和String类型
无法通过上述注解实现
@Value
:- 作用:
- 注入基本数据类型和String类型数据
- 属性:
- 用于指定数据的值,它可以使用spring中的SpEL表达式(
写法:${表达式}
)
- 用于指定数据的值,它可以使用spring中的SpEL表达式(
- 作用:
1.3用于改变作用范围的注解
@Scope
注解- 作用:
- 用于指定bean的范围
- 属性:
- value:用于指定范围的取值,
"singleton","prototype","request","session","globalsession"
- value:用于指定范围的取值,
- 作用:
1.4 和生命周期相关的注解(了解)
-
@PreDestroy
注解- 作用:
- 用于指定销毁方法
- 作用:
-
PostConstruct
注解- 作用
- 用于指定初始化方法
- 作用
1.5Spring中注解和XML的比较
-
注解的优势:
- 配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。
-
XML的优势:
- 修改时,不用改源码。不涉及重新编译和部署。
基于XML的配置 | 基于注解的配置 | |
---|---|---|
Bean 定义 | <bean id = "..." class = "..." /> | @Component、@Controller、@Service、@Repository |
Bean 名称 | 通过 id 或者 name 属性指定 | @Component("person") |
Bean 注入 | 通过<property> 或者<constructor-arg> 标签注入 | @Autowired、@Qualifier、@Resource |
Bean 作用范围 | 通过scope 属性指定 | @Scope |
Bean 生命周期 | 通过 init-method 或者destroy-method 属性指定初始化和销毁方法 | @PostConstruct、@PreDestroy |
Bean 适合场景 | Bean 来自于第三方,无法修改源码 | Bean 的实现类由自己开发 |
2.使用spring的IOC实现账户的CRUD操作
2.1XML的方式
-
整体目录结构图如下:
-
首先在pom.xml中导入相关依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>day02_eesy_02account_xmlioc</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.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.26</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>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
</dependencies>
</project>
- 创建数据库表并创建其对应的实体类:
create table account(
id int primary key auto_increment,
name varchar(40),
balance doule
)character set utf8 collate utf8_general_ci;
insert into account(name,balance) values('aaa',1000);
insert into account(name,balance) values('bbb',1000);
insert into account(name,balance) values('ccc',1000);
/**
* 账户的实体类
*/
public class Account implements Serializable {
private Integer id;
private String name;
private float money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getMoney() {
return money;
}
public void setMoney(float money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
- 编写持久层接口及其实现类:
/**
* 持久层接口类
*/
public interface IAccountDao {
/**
* 查询所有
* @return
*/
List<Account> findAllAccount();
/**
* 查询一个
* @return
*/
Account findAccountById(Integer accountId);
/**
* 增
*/
void saveAccount(Account account);
/**
* 删
* @param accountId
*/
void deleteAccount(Integer accountId);
/**
* 改
* @param account
*/
void updateAccount(Account 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 (Exception e) {
throw new RuntimeException(e);
}
}
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);
}
}
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);
}
}
public void deleteAccount(Integer accountId) {
try {
runner.update("delete from account where id = ?", accountId);
}catch (Exception 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 (Exception e) {
throw new RuntimeException(e);
}
}
}
- 编写业务层接口及其实现类:
public interface IAccountService {
/**
* 查询所有
* @return
*/
List<Account> findAllAccount();
/**
* 查询一个
* @return
*/
Account findAccountById(Integer accountId);
/**
* 增
*/
void saveAccount(Account account);
/**
* 删
* @param accountId
*/
void deleteAccount(Integer accountId);
/**
* 改
* @param account
*/
void updateAccount(Account account);
}
/**
* 账户的业务层实现类
*/
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 accountId) {
return accountDao.findAccountById(accountId);
}
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
public void deleteAccount(Integer accountId) {
accountDao.deleteAccount(accountId);
}
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
}
- 编写spring的配置文件
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="com.zut.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<bean id="accountDao" class="com.zut.dao.impl.AccountDaoImpl">
<property name="runner" ref="queryRunner"></property>
</bean>
<!--配置QueryRunner-->
<bean id="queryRunner" 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/student"></property>
<property name="user" value="root"></property>
<property name="password" value="ljt074517"></property>
</bean>
</beans>
- 测试代码如下:
/**
* 使用junit单元测试
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class AccountServiceTest {
@Autowired
private IAccountService as;
@Test
public void testfindAll() {
List<Account> accounts = as.findAllAccount();
for (Account account:accounts){
System.out.println(account);
}
}
@Test
public void testfindOne() {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.得到service
IAccountService as = ac.getBean("accountService",IAccountService.class);
Account account = as.findAccountById(1);
System.out.println(account);
}
@Test
public void testSave() {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.得到service
IAccountService as = ac.getBean("accountService",IAccountService.class);
Account account = new Account();
account.setName("test");
account.setMoney(123456);
as.saveAccount(account);
}
@Test
public void testUpdate() {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.得到service
IAccountService as = ac.getBean("accountService",IAccountService.class);
Account account = as.findAccountById(4);
account.setMoney(1200);
account.setName("test2");
as.updateAccount(account);
}
@Test
public void testDelete() {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.得到service
IAccountService as = ac.getBean("accountService",IAccountService.class);
as.deleteAccount(4);
}
}
2.2注解+XML的方式
- 配置文件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">
<!-- 开启注解 -->
<context:component-scan base-package="com.zut"></context:component-scan>
<!--配置QueryRunner-->
<bean id="queryRunner" 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/student"></property>
<property name="user" value="root"></property>
<property name="password" value="ljt074517"></property>
</bean>
</beans>
这里
QueryRunner
和ComboPooledDataSource
第三方类是存在于jar包中的,无法在它们的类上加上注解,所以还需要XML配置文件。
- 持久层代码:
@Repository(value = "accountDao")
public class AccountDaoImpl implements IAccountDao {
@Autowired
private QueryRunner runner;
//省略.............
- 业务层代码:
@Service(value = "accountService")
public class AccountServiceImpl implements IAccountService {
@Autowired
private IAccountDao accountDao;
//省略........
使用
@Repository和@Service
将标注的类存入到容器中去,@Autowired
来进行依赖注入。代替了xml配置的<bean>
标签
2.3纯注解配置
-
如果要实现纯注解的配置,需要将上面bean.xml中的配置用注解来表示,这时我们引入一些新的注解:
-
@Configuration
:- 作用:指定当前类是一个配置类(用一个类来代替XML配置文件)
- 细节:当配置类作为
AnnotationConfigApplicationContext
对象创建的参数时,该注解可以不写 。
-
@ComponentScan
:- 作用:用于通过注解指定spring在创建时要扫描的包
- 属性:
- value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包我们使用此注解就等同于在xml中配置了
<context:component-scan base-package=""></context:componentn>
- value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包我们使用此注解就等同于在xml中配置了
-
@Bean
- 作用:用于把当前方法的返回值作为bean对象并存入spring容器中
- 属性:
- name:用于指定bean的
id
。默认值为当前方法的名称
- name:用于指定bean的
- 细节:当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象,查找的方式和Autowired注解是一样的
-
@Import
- 作用:用于导入其他的配置类
- 属性:
- value:用于指定其他注解的字节码,当使用import后,有Import注解的类就是父配置类
-
@PropertySource
- 作用:用于指定properties文件的位置
- 属性:
- value:指定文件的名称和路径
- 有了上面的这些注解后,我们可以把bean.xml改造为以下两个配置类。
//@Configuration
@ComponentScan("zut")
@Import(JDBCconfig.class)
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {
}
/**
* 和spring连接数据库相关的配置类
*/
//这里的Configuration注解就不能省略,虽然已经配置了对这个包进行了扫描,但是首先它要是一个配置类,才会对里面的注解进行扫描
//没有Configuration,spring扫描这个包也不会识别bean注解
@Configuration
public class JDBCconfig {
@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 = "queryRunner")
@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);
}
}
}