在独立的环境中通过使用基于 Java 的配置创建和使用Spring 容器

创建一个名为com.wiley.beginning.spring.ch2 的程序包,并在其中创建如下所示的
Java 类:
public class Account {
private long id;
private String ownerName;
private double balance;
private Date accessTime;
Spring 入门经典
20
//getters & setters...
}
public interface AccountDao {
public void insert(Account account);
public void update(Account account);
public void update(List<Account> accounts);
public void delete(long accountId);
public Account find(long accountId);
public List<Account> find(List<Long> accountIds);
public List<Account> find(String ownerName);
public List<Account> find(boolean locked);
}
public class AccountDaoInMemoryImpl implements AccountDao {
private Map<Long,Account> accountsMap = new HashMap<>();
{
Account account1 = new Account();
account1.setId(1L);
account1.setOwnerName("John");
account1.setBalance(10.0);
Account account2 = new Account();
account2.setId(2L);
account2.setOwnerName("Mary");
account2.setBalance(20.0);
accountsMap.put(account1.getId(), account1);
accountsMap.put(account2.getId(), account2);
}
@Override
public void update(Account account) {
accountsMap.put(account.getId(), account);
}
@Override
public Account find(long accountId) {
return accountsMap.get(accountId);
}
//other method implementations
}
第2 章使用 Spring 进行依赖注入
21
public interface AccountService {
public void transferMoney(
long sourceAccountId, long targetAccountId, double amount);
public void depositMoney(long accountId, double amount)
throws Exception;
public Account getAccount(long accountId);
}
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transferMoney(
long sourceAccountId, long targetAccountId, double amount) {
Account sourceAccount = accountDao.find(sourceAccountId);
Account targetAccount = accountDao.find(targetAccountId);
sourceAccount.setBalance(sourceAccount.getBalance() - amount);
targetAccount.setBalance(targetAccount.getBalance() + amount);
accountDao.update(sourceAccount);
accountDao.update(targetAccount);
}
@Override
public void depositMoney(long accountId, double amount) throws Exception {
Account account = accountDao.find(accountId);
account.setBalance(account.getBalance() + amount);
accountDao.update(account);
}
@Override
public Account getAccount(long accountId) {
return accountDao.find(accountId);
}
}
(4) 创建如下所示的基于Java 的Bean 定义类:
@Configuration
public class Ch2BeanConfiguration {
@Bean
public AccountService accountService() {
AccountServiceImpl bean = new AccountServiceImpl();
bean.setAccountDao(accountDao());
return bean;
Spring 入门经典
22
}
@Bean
public AccountDao accountDao() {
AccountDaoInMemoryImpl bean = new AccountDaoInMemoryImpl();
//depedencies of accountDao bean will be injected here...
return bean;
}
}
(5) 使用main 方法创建一个Main 类,并将上一步骤所创建的基于Java 的配置类作为
构造函数参数来实例化Spring 容器:
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(Ch2BeanConfiguration.class);
}
}
(6) 在Spring 容器内部访问accountService Bean,如下所示:
AccountService accountService =
applicationContext.getBean("accountService", AccountService.class);
System.out.println("Before money transfer");
System.out.println("Account 1 balance :" +
accountService.getAccount(1).getBalance());
System.out.println("Account 2 balance :" +
accountService.getAccount(2).getBalance());
accountService.transferMoney(1, 2, 5.0);
System.out.println("After money transfer");
System.out.println("Account 1 balance :" +
accountService.getAccount(1).getBalance());
System.out.println("Account 2 balance :" +
accountService.getAccount(2).getBalance());
示例说明
首先,我们创建了一个名为Account 的域类。然后,分别使用AccountDaoInMemoryImpl
类和AccountServiceImpl 类创建了接口AccountDao(对应DAO 层)和AccountService(对应服
务层)。AccountService 声明了一个transferMoney 方法,该方法可以在由accountIds 标识的
两个Account 对象之间移动给定数额的资金。AccountServiceImpl 类首先需要获取这两个
Account 对象并在完成转账操作之后更新这些对象。因此,AccountServiceImpl 依赖
第2 章使用 Spring 进行依赖注入
23
AccountDao 接口,该接口声明了用来在给定Account 上执行基本持久化操作的方法以及用
来查找Account 实例的Finder 方法(通过使用一些查询参数)。
然后创建一个名为Ch2BeanConfiguration的Spring Bean定义类并使用org.springframework.
context.annotation.Configuration 注解进行标记。该注解告诉Spring,该类是一个Bean 并且
包含配置元数据。在该配置类中,创建了两个工厂方法并使用org.springframework.context.
annotation.Bean 注解进行标记。这些方法在启动期间被Spring 容器调用,而返回值则被视
为Spring 管理的Bean。默认情况下,方法的名称就是Bean 的名称。而在工厂方法中,首
先通过调用Setter 方法设置所需的依赖项,然后使用具体类创建一个Bean 并将其返回。此
外,依赖项还可以构造函数参数的形式赋予。
注意,工厂方法的返回类型被定义为接口而不是具体类。虽然使用接口并不是强制性
的,但这样做可以更容易地使用不同的Bean 实现类来配置系统。例如,可以添加另一个
带有新配置元数据的Bean 定义,而该定义返回实现了AccountDao 接口的JDBC,同时
AccountService Bean 仍然保持工作,而不必对其实现过程或Bean 定义进行任何修改。
你可能已经注意到,AccountService Bean 的AccountDao 依赖是通过在AccountServic()
方法中调用accountDao()方法而获取的。有些人可能会认为,如果其他工厂方法也多次调
用accountDao()方法,那么在系统中不是就有多个accountDao Bean 了吗?如果仅想要这些
Bean 中的一个实例作为一般情况下的服务和存储库Bean,那么这难道不是一个很大的问
题吗?这些问题的答案是没有的,在本系统中,针对一个Bean 定义并不会有多个Bean 实
例。默认情况下,每一个Bean 都有一个被称为单实例作用域(singleton scope)的单个实例 (本
章的后面将会详细介绍Bean 作用域)。目前只需要知道仅会生成accountDao Bean 的一个实
例,多个不同方法调用并不会创建多个实例。Spring 在运行时动态地扩展@Configuration
类并且使用@Bean 注解来重写工厂方法,以便处理该问题。因此,不管是从类中多次调用
工厂方法,还是从其他@Configuration 类中多次调用工厂方法,在第一次创建了Bean 实例
之后就不会再创建任何新的Bean 实例。对于连续调用,工厂方法将会返回相同的Bean
实例。
接下来,创建Spring 容器实例。如前所述,Spring 容器也是一个Java 对象,并负责
管理应用程序中的其他对象。org.springframework.context.ApplicationContext 接口表示
Spring 接口;事实上,术语Spring Container 和AppliationContext 通常可以交换使用。可
以根据ApplicationContext 实例处理Bean 配置元数据文件或类的方式以及处理的位置来选
择使用ApplicationContext 的多个不同的实现过程。org.springframework.context.annotation.
AnnotationConfigApplicationContext 类被用来处理基于Java 的配置元数据类。虽然,这里仅
提供了一个,但我可以将多个配置类作为输入参数提供给AnnotationConfigApplicationContext
类。
Spring 容器(或者说ApplicationContext)在创建之后就可以使用了。目前,可以通过
Spring 容器获取Bean,并使用它们满足系统需求。获取Spring 管理的Bean 的过程被称为
“Bean 查找”。本章的后面将详细介绍Bean 查找。此时只需要知道可以通过名称获取对任
何Bean 的引用。ApplicationContext.getBean()方法用来执行Bean 查找。除了向该方法传入
需要查找的Bean 名称之外,还要提供类型参数,以便自动将返回的Bean 实例转换为该类

型。在获取了对某个Bean 的引用后,就可以调用Bean 契约(contract)中的任何方法。可以
调用transferMoney()方法并将accountIds 和amount 作为输入参数。
也可以创建并使用基于XML 的配置元数据。下面所示的“试一试”演示了具体的操

作过程。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值