package com.zzxx.dao;
import com.zzxx.domain.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
public class AccountDaoImpl implements AccountDAO {
private JdbcTemplate jdbcTemplate;
@Override
public Account findById(int id) {
String sql = "select * from account where id = ?";
List<Account> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Account>(Account.class), id);
return list.size() > 0?list.get(0):null;
}
@Override
public void increaseMoney(int toId, double money) {
String sql = "update account set money = money + ? where id = ?";
jdbcTemplate.update(sql, money, toId);
}
@Override
public void decreaseMoney(int fromId, double money) {
String sql = "update account set money = money - ? where id = ?";
jdbcTemplate.update(sql, money, fromId);
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
package com.zzxx.domain;
public class Account {
private Integer id;
private Double money;
@Override
public String toString() {
return "Account{" +
"id=" + id +
", money=" + money +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
}
package com.zzxx.service;
import com.zzxx.dao.AccountDAO;
import com.zzxx.domain.Account;
public class AccountServiceImpl implements AccountService {
private AccountDAO accountDAO;
@Override
public Account selectById(int id) {
return accountDAO.findById(id);
}
@Override
public void transfer(int fromId, int toId, double money) {
accountDAO.decreaseMoney(fromId, money);
accountDAO.increaseMoney(toId, money);
}
public void setAccountDAO(AccountDAO accountDAO) {
this.accountDAO = accountDAO;
}
}
<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 https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="accountService" class="com.zzxx.service.AccountServiceImpl">
<property name="accountDAO" ref="accountDao"/>
bean>
<bean id="accountDao" class="com.zzxx.dao.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg name="dataSource" ref="dataSource"/>
bean>
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
bean>
beans>
package com.zzxx.test;
import com.zzxx.domain.Account;
import com.zzxx.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
// 模拟web层
public class WebTest {
@Test
public void selectAccount() {
// 先获得service对象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountService accountService = ac.getBean(AccountService.class);
// 模拟web层调用service层方法
Account account = accountService.selectById(1);
System.out.println(account);
}
}
学习基于注解的 IOC 配置,⼤家脑海⾥⾸先得有⼀个认知,即注解配置和 xml 配置要实现的功能都是⼀样的,都是要降低程序间的耦合。只是配置的形式不⼀样。
关于实际的开发中到底使⽤ xml 还是注解,每家公司有着不同的使⽤习惯。所以这两种配置⽅式我们都需要掌握。
注意:在基于注解的配置中,我们还要多添加⼀个 aop 的 jar 包。但是由于我们使⽤的是maven⼯程,在添加spring-context依赖时,⾃动添加了aop依赖,所以这⼀步可以省略。
注意:当我们使⽤注解注⼊时,set ⽅法不⽤写
注意:基于注解整合时,导⼊约束时需要多导⼊⼀个 context 名称空间下的约束。
<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
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.zzxx"/>
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"/>
bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///spring"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
bean>
beans>
相当于:
作⽤:
把资源让 spring 来管理。相当于在 xml 中配置⼀个 bean。
属性:
value:指定 bean 的 id。如果不指定 value 属性,
默认 bean 的 id 是当前类的类名。⾸字⺟⼩写。
他们三个注解都是针对⼀个的衍⽣注解,他们的作⽤及属性都是⼀模⼀样的。
他们只不过是提供了更加明确的语义化。
@Controller:⼀般⽤于表现层的注解。
@Service:⼀般⽤于业务层的注解。
@Repository:⼀般⽤于持久层的注解。
细节:如果注解中有且只有⼀个属性要赋值时,且名称是 value,value 在赋值是可以不写。
相当于:
<property name="" ref="">
<property name="" value="">
作⽤: ⾃动按照类型注⼊。当使⽤注解注⼊属性时,set ⽅法可以省略。它只能注⼊其他 bean 类型。当有多个类型匹配时,使⽤要注⼊的对象变量名称作为 bean 的 id,在 spring 容器查找,找到了也可以注⼊成功。找不到就报错。
作⽤:
在⾃动按照类型注⼊的基础之上,再按照 Bean 的 id 注⼊。它在给字段注⼊
时不能独⽴使⽤,必须和 @Autowire ⼀起使⽤;但是给⽅法参数注⼊时,
可以独⽴使⽤。
属性:
value:指定 bean 的 id。
作⽤:
直接按照 Bean 的 id 注⼊。它也只能注⼊其他 bean 类型。
属性:
name:指定 bean 的 id。
作⽤:
注⼊基本数据类型和 String 类型数据的。
属性:
value:⽤于指定值。
相当于:
作⽤:
指定 bean 的作⽤范围。
属性:
value:指定范围的值。
取值:singleton prototype request session globalsession
相当于:
作⽤:
⽤于指定初始化⽅法。
作⽤: ⽤于指定销毁⽅法。
注解的优势:
配置简单,维护⽅便(我们找到类,就相当于找到了对应的配置)。
XML 的优势:
修改时,不⽤改源码。不涉及重新编译和部署。
基于注解的spring IOC配置中,bean对象的特点和基于XML配置是⼀模⼀样的。
写到此处,基于注解的 IOC 配置已经完成,但是⼤家都发现了⼀个问题:我们依然离不开 spring的 xml 配置⽂件,那么能不能不写这个 bean.xml,所有配置都⽤注解来实现呢?
我们发现,之所以我们现在离不开 xml 配置⽂件,是因为我们有⼀句很关键的配置:
作⽤:
⽤于指定当前类是⼀个 spring 配置类,当创建容器时会从该类上加载注解。
获取容器时需要使⽤AnnotationApplicationContext(有@Configuration
注解的类.class)。
属性:
value:⽤于指定配置类的字节码
作⽤:
⽤于指定 spring 在初始化容器时要扫描的包。作⽤和在 spring 的 xml
配置⽂件中的:
是⼀样的。
属性:
basePackages:⽤于指定要扫描的包。和该注解中的 value 属性作⽤⼀样。
作⽤:
该注解只能写在⽅法上,表明使⽤此⽅法创建⼀个对象,并且放
⼊ spring 容器。
属性:
name:给当前 @Bean 注解⽅法创建的对象指定⼀个名称(即 bean 的 id)。
示例代码:
/**
* 连接数据库的配置类
* @author bonnie
**/
public class JdbcConfig {
/**
* 创建⼀个数据源,并存⼊ spring 容器中
* @return
*/
@Bean(name = "dataSource")
public DataSource createDataSource() {
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setUser("root");
ds.setPassword("root");
ds.setDriverClass("com.mysql.cj.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql:///spring");
return ds;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 创建⼀个 QueryRunner,并且也存⼊ spring 容器中
* @param dataSource
* @return
*/
@Bean(name = "queryRunner")
public QueryRunner createQueryRunner(DataSource dataSource) {
return new QueryRunner(dataSource);
}
}
作⽤:
⽤于加载 .properties ⽂件中的配置。例如我们配置数据源时,可以把连接
数据库的信息写到 properties 配置⽂件中,就可以使⽤此注解指定
properties 配置⽂件的位置。
属性:
value[]:⽤于指定 properties ⽂件位置。如果是在类路径下,
需要写上 classpath:
/**
* 连接数据库的配置类
* @author bonnie
**/
@PropertySource("classpath:jdbc.properties")
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;
/**
* 创建⼀个数据源,并存⼊ spring 容器中
* @return
*/
@Bean(name = "dataSource")
public DataSource createDataSource() {
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setUser(username);
ds.setPassword(password);
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
return ds;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
作⽤:
⽤于导⼊其他配置类,在引⼊其他配置类时,可以不⽤再写 @Configuration
注解。当然,写上也没问题。
属性:
value[]:⽤于指定其他配置类的字节码。