史上最简单的 Spring 教程 | 第三篇: 使用 spring 的 IOC 解决程序耦合

3.1 案例的前期准备

本章我们使用的案例是,账户的业务层和持久层的依赖关系解决。在开始 spring 的配置之前,我们要先准备一下环境。由于我们是使用 spring 解决依赖关系,并不是真正的要做增删改查操作,所以此时我们没必要写实体类。并且我们在此处使用的是 java 工程,不是 java web 工程。

3.1.1 准备 spring 的开发包

官网:http://spring.io/
下载地址:
http://repo.springsource.org/libs-release-local/org/springframework/spring
解压:(Spring 目录结构:)
* docs :API 和开发规范
* libs :jar 包和源码.
* schema :约束.

在这里插入图片描述

特别说明: spring5 版本是用 jdk8 编写的,所以要求我们的 jdk 版本是 8 及以上。 同时 tomcat 的版本要求 8.5 及以上。

3.1.2 创建业务层接口和实现类

/**
* 账户的业务层接口
* @Version 1.0
*/
public interface IAccountService {
/**
* 保存账户(此处只是模拟,并不是真的要保存)
*/
void saveAccount();
}
/**
* 账户的业务层实现类
* @Version 1.0
*/
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao = new AccountDaoImpl();//此处的依赖关系有待解决
@Override
public void saveAccount() {
accountDao.saveAccount();
} }

3.1.3 创建持久层接口和实现类

/**
* 账户的持久层接口
* @Version 1.0
*/
public interface IAccountDao {
/**
* 保存账户
*/
void saveAccount();
}
/**
* 账户的持久层实现类
* @Version 1.0
*/
public class AccountDaoImpl implements IAccountDao {
@Override
public void saveAccount() {
System.out.println("保存了账户");
} }

3.2 基于 XML 的配置

3.2.1 第一步:拷贝必备的 jar 包到工程的 lib 目录中
史上最简单的 Spring 教程 | 第三篇: 使用 spring 的 IOC 解决程序耦合_第1张图片
3.2.2 第二步:在类的根路径下创建一个任意名称的 xml 文件(不能是中文)
史上最简单的 Spring 教程 | 第三篇: 使用 spring 的 IOC 解决程序耦合_第2张图片
史上最简单的 Spring 教程 | 第三篇: 使用 spring 的 IOC 解决程序耦合_第3张图片




3.2.3 第三步:让 spring 管理资源,在配置文件中配置 service 和 dao

 
 


 

3.2.4 测试配置是否成功

/**
* 模拟一个表现层
* @Version 1.0
*/
public class Client {
/**
 * 使用 main 方法获取容器测试执行
* */
public static void main(String[] args) {
//1.使用 ApplicationContext 接口,就是在获取 spring 容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.根据 bean 的 id 获取对象
IAccountService aService = (IAccountService) ac.getBean("accountService");
System.out.println(aService);
IAccountDao aDao = (IAccountDao) ac.getBean("accountDao");
System.out.println(aDao);
} }
运行结果:
com.yu.service.impl.AccountServiceImpl@244141a
com.yu.dao.impl.AccountDaoImpl@21123asdf

3.3Spring 基于 XML 的 IOC 细节

3.3.1 spring 中工厂的类结构图
史上最简单的 Spring 教程 | 第三篇: 使用 spring 的 IOC 解决程序耦合_第4张图片
史上最简单的 Spring 教程 | 第三篇: 使用 spring 的 IOC 解决程序耦合_第5张图片
3.3.1.1 BeanFactory 和 ApplicationContext 的区别

BeanFactory 才是 Spring 容器中的顶层接口。
ApplicationContext 是它的子接口。
BeanFactory和 ApplicationContext 的区别:
创建对象的时间点不一样。
ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。
BeanFactory:什么使用什么时候创建对象。

3.3.1.2 ApplicationContext 接口的实现类

ClassPathXmlApplicationContext:
它是从类的根路径下加载配置文件 推荐使用这种
FileSystemXmlApplicationContext:
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
AnnotationConfigApplicationContext:
当我们使用注解配置容器对象时,需要使用此类来创建 spring容器。它用来读取注解。

3.3.2 IOC 中 bean 标签和管理对象细节

3.3.2.1 bean 标签

作用: 用于配置对象让 spring 来创建的。 默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。 属性:
id:给对象在容器中提供一个唯一标识。用于获取对象。 class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
scope:指定对象的作用范围。

  • singleton :默认值,单例的.
  • prototype :多例的.
  • request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
  • session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
  • global session :WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么 globalSession 相当于 session. init-method:指定类中的初始化方法名称。
    destroy-method:指定类中销毁方法名称。

3.3.2.2 bean 的作用范围和生命周期

单例对象:scope=“singleton” 一个应用只有一个对象的实例。它的作用范围就是整个引用。 生命周期:
对象出生:当应用加载,创建容器时,对象就被创建了。 对象活着:只要容器在,对象一直活着。 对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
多例对象:scope=“prototype” 每次访问对象时,都会重新创建对象实例。 生命周期: 对象出生:当使用对象时,创建新的对象实例。
对象活着:只要对象在使用中,就一直活着。 对象死亡:当对象长时间不用时,被 java 的垃圾回收器回收了。

3.3.2.3 实例化 Bean 的三种方式

第一种方式:使用默认无参构造函数
 
第二种方式:spring 管理静态工厂-使用静态工厂的方法创建对象
/**
* 模拟一个静态工厂,创建业务层实现类
*/
public class StaticFactory {
public static IAccountService createAccountService(){
return new AccountServiceImpl();
} }
 
第三种方式:spring 管理实例工厂-使用实例工厂的方法创建对象
/**
* 模拟一个实例工厂,创建业务层实现类
* 此工厂创建对象,必须现有工厂实例对象,再调用方法
*/
public class InstanceFactory {
public IAccountService createAccountService(){
return new AccountServiceImpl();
} }
  

3.3.3 spring 的依赖注入

3.3.3.1 依赖注入的概念

依赖注入:Dependency Injection。它是 spring 框架核心 ioc 的具体实现。
我们的程序在编写时,通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。
ioc 解耦只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。
那这种业务层和持久层的依赖关系,在使用 spring 之后,就让 spring 来维护了。
简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。

3.3.3.2 构造函数注入

顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置
的方式,让 spring 框架来为我们注入。具体代码如下:
/**
*/
public class AccountServiceImpl implements IAccountService {
private String name;
private Integer age;
private Date birthday;
public AccountServiceImpl(String name, Integer age, Date birthday) {
this.name = name;
this.age = age;
this.birthday = birthday; }
@Override
public void saveAccount() {
System.out.println(name+","+age+","+birthday);
} }
    
 

3.3.3.3 set 方法注入

顾名思义,就是在类中提供需要注入成员的 set 方法。具体代码如下:
/** */
public class AccountServiceImpl implements IAccountService {
private String name;
private Integer age;
private Date birthday;
public void setName(String name) {
this.name = name; }
public void setAge(Integer age) {
this.age = age; }
public void setBirthday(Date birthday) {
this.birthday = birthday; }
@Override
public void saveAccount() {
System.out.println(name+","+age+","+birthday);
} }
    
 

3.3.3.4注入集合属性

顾名思义,就是给类中的集合成员传值,它用的也是set方法注入的方式,只不过变量的数据类型都是集合。
我们这里介绍注入数组,List,Set,Map,Properties。具体代码如下:
/***/
public class AccountServiceImpl implements IAccountService {
private String[] myStrs;
private List myList;
private Set mySet;
private Map myMap;
private Properties myProps;
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs; }
public void setMyList(List myList) {
this.myList = myList; }
public void setMySet(Set mySet) {
this.mySet = mySet; }
public void setMyMap(Map myMap) {
this.myMap = myMap; }
public void setMyProps(Properties myProps) {
this.myProps = myProps; }
@Override
public void saveAccount() {
System.out.println(Arrays.toString(myStrs));
System.out.println(myList);
System.out.println(mySet);
System.out.println(myMap);
System.out.println(myProps);
} }
 

  AAA BBB CCC


   AAA BBB CCC


  AAA BBB CCC


   aaa bbb



   bbb




你可能感兴趣的:(Spring)