1.0 这里说的SSM,指的是
(Spring+SpringMVC+MyBatis)框架集,由Spring、MyBatis两个开源框架整合而成(SpringMVC是Spring中的部分内容)。
2.0 Sring学习内容
- spring框架的概述以及spring中基于XML的IOC配置
- spring中基于注解的IOC和ioc的案例
- spring中的aop和基于XML以及注解的AOP配置
- spring中的JdbcTemlate以及Spring事务控制
Spring学习使用的是IntelliJ IDEA。我用的是当下最新版,官网下的。激活方式很多,自行百度。
3.0 spring是什么
Spring 是分层的 Java SE/EE 应用 full-stack(全栈级别) 轻量级开源框架,以 IoC(Inverse Of Control:反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 Spring MVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架。
4.0 spring的两大核心
5.0 spring的发展历程和优势
这一节主要就是些废话。
5.1 发展历程
1997 年 IBM 提出了 EJB 的思想(23年前)
1998 年,SUN 制定开发标准规范 EJB1.0
1999 年,EJB1.1 发布
2001 年,EJB2.0 发布
2003 年,EJB2.1 发布
2006 年,EJB3.0 发布
Rod Johnson(spring 之父)
Expert One-to-One J2EE Design and Development(2002)
阐述了 J2EE 使用 EJB 开发设计的优点及解决方案
Expert One-to-One J2EE Development without EJB(2004)
阐述了 J2EE 开发不使用 EJB 的解决方式(Spring 雏形)
2017 年 9 月份发布了 spring 的最新版本 spring 5.0 通用版(GA)
5.2 spring 的优势
<方便解耦,简化开发>
通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
< AOP编程的支持>
通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付。
<声明式事务的支持>
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量。
<方便程序的测试>
可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。
<方便集成各种优秀框架>
Spring 可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的直接支持。
<降低 JavaEE API 的使用难度>
Spring 对 JavaEE API(如 JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些 API 的使用难度大为降低。
< Java 源码是经典学习范例 >
Spring 的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对 Java 设计模式灵活运用以及对 Java 技术的高深造诣。它的源代码无意是 Java 技术的最佳实践的范例。
6.0 spring体系结构
所有的其他部分都离不开核心容器,所有必须先学懂容器,才能说会使用Spring。
7.0 新建一个项目
打开IntelliJ IDEA,创建一个新的Project:
我已经创建过了,所有提示我不能创建同一个项目名称。
等待一会,创建完毕。
新建一个数据库。即使是示范代码也是操作真实数据库。
先看一个简单的实现。
在pom.xml中配置一下mysql的驱动:
<?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>com.edp</groupId>
<artifactId>spring_study</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<!--打包方式选择jar-->
<dependencies>
<!--设置mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
启动类就一个jdbc操作:
package com.edp.jdbc;
import java.sql.*;
/**
* 程序的耦合
*/
public class JdbcDemo1 {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
//1.注册驱动
//DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/eesy?useSSL=false&serverTimezone=UTC", "root", "bywwcnll");
//3.获取操作数据库的预处理对象
PreparedStatement pstm = connection.prepareStatement("select * from account");
//4.执行SQL,得到结果集
ResultSet rs = pstm.executeQuery();
//5.遍历结果集
while (rs.next()) {
System.out.println(rs.getString("name"));
}
//6.释放资源,先开的后关
rs.close();
pstm.close();
connection.close();
}
}
运行:
但是,如果我们把mysql的依赖注释掉,会发现,程序无法运行,报编译错误。
这里涉及到的一个重点——耦合
8.0 程序的耦合及解耦
官方意思超级长,如下:
耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调
用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关
系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立
性)。耦合性存在于各个领域,而非软件设计中独有的,但是我们只讨论软件工程中的耦合。
在软件工程中,耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计
应使类和构件之间的耦合最小。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个
准则就是高内聚低耦合。
它有如下分类:
(1)内容耦合。当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而转入另
一个模块时,这样的耦合被称为内容耦合。内容耦合是最高程度的耦合,应该避免使用之。
(2)公共耦合。两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。在具有大
量公共耦合的结构中,确定究竟是哪个模块给全局变量赋了一个特定的值是十分困难的。
(3) 外部耦合 。一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传
递该全局变量的信息,则称之为外部耦合。
(4) 控制耦合 。一个模块通过接口向另一个模块传递一个控制信号,接受信号的模块根据信号值而进
行适当的动作,这种耦合被称为控制耦合。
(5)标记耦合 。若一个模块 A 通过接口向两个模块 B 和 C 传递一个公共参数,那么称模块 B 和 C 之间
存在一个标记耦合。
(6) 数据耦合。模块之间通过参数来传递数据,那么被称为数据耦合。数据耦合是最低的一种耦合形
式,系统中一般都存在这种类型的耦合,因为为了完成一些有意义的功能,往往需要将某些模块的输出数据作为另
一些模块的输入数据。
(7) 非直接耦合 。两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实
现的。
总结:
耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须
存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。
内聚与耦合
内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从
功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。耦合是软件
结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通
过接口的数据。 程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之
间的相互依存度却要不那么紧密。
内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块同其他
模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合
现在主要考虑类之间的依赖问题(还有方法间的依赖,)
8.1 解耦:降低程序间的依赖关系。
实际开发中,应该做到:
编译器不依赖,运行时才依赖。
我们在开发中,有些依赖关系是必须的,有些依赖关系可以通过优化代码来解除的。
解耦的思路:
- 使用反射来创建对象,而避免使用new关键字。
- 读取配置文件读取要创建的对象全限定类名。
8.2 曾经案例中问题
以下案例是一种反射加注解的方式搭建的工厂模式,模拟有web层,业务层,和持久层(Dao层),并创建一个工厂类来创建新的业务层和dao层的类:
ui包下是模拟web层的意思。
AccountDaoImpl.java
package com.edp.dao.impl;
import com.edp.dao.IAccountDao;
import org.omg.Messaging.SyncScopeHelper;
/**
* @author EdPeng
* @Title:
* @Package
* @Description: 账户持久层实现类
* @date 2020/2/23下午 5:45
*/
public class AccountDaoImpl implements IAccountDao {
@Override
public void saveAccount() {
System.out.println("保存了账户。");
}
}
AccountDao.java
package com.edp.dao;
/**
* @author EdPeng
* @Title:
* @Package
* @Description: 账户持久层接口
* @date 2020/2/23下午 5:43
*/
public interface IAccountDao {
/**
* @Description: 模拟保存账户
* @author EdPeng
* @date 2020/2/23 下午 5:44
*/
void saveAccount();
}
IAccountServiceImpl .java
package com.edp.service.impl;/**
* @Title:
* @Package
* @Description:
* @author EdPeng
* @date 2020/2/23下午 5:40
*/
import com.edp.dao.IAccountDao;
import com.edp.dao.impl.AccountDaoImpl;
import com.edp.service.IAccountService;
/**
* @Description: 账户业务层实现类
* @author EdPeng
* @date 2020/2/23 下午 6:33
*/
public class IAccountServiceImpl implements IAccountService {
private IAccountDao accountDao = new AccountDaoImpl();
@Override
public void saveAccount() {
accountDao.saveAccount();
}
}
IAccountService .java
package com.edp.service;
/**
* 账户业务层的接口
*/
public interface IAccountService {
/**
* @param
* @return
* @throws
* @Description: 模拟账户保存
* @author EdPeng
* @date 2020/2/23 下午 5:38
*/
void saveAccount();
}
Client.java
package com.edp.ui;
import com.edp.service.IAccountService;
import com.edp.service.impl.IAccountServiceImpl;
/**
* @author EdPeng
* @Title:
* @Package
* @Description: 模拟一个表现层,用于调用业务层
* @date 2020/2/23下午 5:48
*/
public class Client {
public static void main(String[] args) {
IAccountService accountService = new IAccountServiceImpl();
accountService.saveAccount();
}
}
重点来了,配置一个properties文件,bean.properties
accountService =com.edp.service.impl.IAccountServiceImpl
accountDao =com.edp.dao.impl.AccountDaoImpl
在工厂类,通过反射,实现一定程度的解耦。
BeanFactory.java
package com.edp.factory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* @author EdPeng
* @Title:
* @Package
* @Description: 一个创建Bean对象的工厂
* JavaBean >> 实体类
* @date 2020/2/23下午 5:51
* 一个javabean类,可重用组件
* 创建我们的service和dao对象
* 第一个:需要一个配置文件来配置文明的service和dao
* 配置内容:唯一标识=全限定类名(key=value)
* 第二个:通过读取配置文件中的配置的内容,来反射创建内容。
* <p>
* 配置文件有两种方式:xml和 properties,这里先采用properties,
*/
public class BeanFactory {
//定义一个Properties对象
private static Properties props;
//使用静态代码块为Properties对象赋值
static {
try {
props = new Properties();
//获取properties文件的流对象
//getClassLoader:类加载器
InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
//load:读取一个流
props.load(inputStream);
} catch (IOException e) {
throw new ExceptionInInitializerError("初始化properties失败");
}
}
/**
* @param
* @return
* @throws
* @Description: 根据Bean的名称获取bean对象
* @author EdPeng
* @date 2020/2/23 下午 6:06
*/
public static Object getBean(String beanName) {
Object bean = null;
try {
String beanPath = props.getProperty((beanName));
//通过反射来创建对象
bean = Class.forName(beanPath).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
}
注意,到现在为止,我们还没有开始编写Spring的代码,只是进行编程原理和思想分析。
8.3下面开始进一步解耦合:
现在,service中依赖了一个具体的实现类,Dao层也依赖了一个具体的实现类。UI中依赖了一个具体的service。
既然已经配置好了 工厂类,那么我们可以先把Client进行解耦。
package com.edp.ui;
import com.edp.factory.BeanFactory;
import com.edp.service.IAccountService;
import com.edp.service.impl.IAccountServiceImpl;
/**
* @author EdPeng
* @Title:
* @Package
* @Description: 模拟一个表现层,用于调用业务层
* @date 2020/2/23下午 5:48
*/
public class Client {
public static void main(String[] args) {
// IAccountService accountService = new IAccountServiceImpl();
IAccountService accountService = (IAccountService) BeanFactory.getBean("accountService");
accountService.saveAccount();
}
}
同理,
这时候,IAccountServiceImpl 可以修改为:
public class IAccountServiceImpl implements IAccountService {
// private IAccountDao accountDao = new AccountDaoImpl();
private IAccountDao accountDao = (IAccountDao) BeanFactory.getBean("accountDao");
@Override
public void saveAccount() {
accountDao.saveAccount();
}
}
运行:
如果我们把IAccountDaoImpl.java 删除,编译是不会报错的,只有运行的时候才会报错。
8.4 针对工厂模式的问题进行升级改造
8.5 针对解耦再进行升级改造
假设,我们修改ui的Client类。
public class Client {
public static void main(String[] args) {
// IAccountService accountService = new IAccountServiceImpl();
for (int i = 0;i<5;i++){
IAccountService accountService = (IAccountService) BeanFactory.getBean("accountService");
System.out.println(accountService);
accountService.saveAccount();
}
}
}
这就存在一个问题,单例模式和多例模式。当我们for语句执行几次之后,程序在多里模式下,会new很多新对象。
解决方法:定义一个容器,存放第一次创建的对象,反复使用,减少内存消耗。整体思路就是,原本由APP(应用程序)控制资源的创建和使用,改为由工厂来管理资源,APP向工厂申请资源使用,通过单例模式实现降低内存和性能消耗。
首先在工厂类中定义一个容器:
//*****定义一个Map,用于存放我们要创建的对象,称之为容器
private static Map<String, Object> beans;
然后对其进行赋值:
//*****实例化容器
beans = new HashMap<String, Object>();
//*****通过枚举,取出配置文件中所有的key
Enumeration<Object> keys = props.keys();
//*****遍历枚举
while (keys.hasMoreElements()) {
String key = keys.nextElement().toString();
//*****根据key获取valve
String beanPath = props.getProperty(key);
//*****反射创建对象
Object value = Class.forName(beanPath).newInstance();
//*****把key和value存入容器中
beans.put(key, value);
再设置一个get方法调用即完成单例模式:
/**
* *****
* @Description: 根据Bean的名称获取bean对象:改造(变成单例模式)
* @author EdPeng
* @date 2020/2/24 下午 11:23
*/
public static Object getBean(String beanName) {
return beans.get(beanName);
}
BeanFactory .java完整代码:
package com.edp.factory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* @author EdPeng
* @Title:
* @Package
* @Description: 一个创建Bean对象的工厂
* JavaBean >> 实体类
* @date 2020/2/23下午 5:51
* 创建文明的service和dao对象
* 第一个:需要一个配置文件来配置文明的service和dao
* 配置内容:唯一标识=全限定类名(key=value)
* 第二个:通过读取配置文件中的配置的内容,来反射创建内容。
* <p>
* 配置文件有两种方式:xml和 properties
*/
public class BeanFactory {
//定义一个Properties对象
private static Properties props;
//*****定义一个Map,用于存放我们要创建的对象,称之为容器
private static Map<String, Object> beans;
//使用静态代码块为Properties对象赋值
static {
try {
props = new Properties();
//获取properties文件的流对象
//getClassLoader:类加载器
InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
//load:读取一个流
props.load(inputStream);
//*****实例化容器
beans = new HashMap<String, Object>();
//*****通过枚举,取出配置文件中所有的key
Enumeration<Object> keys = props.keys();
//*****遍历枚举
while (keys.hasMoreElements()) {
String key = keys.nextElement().toString();
//*****根据key获取valve
String beanPath = props.getProperty(key);
//*****反射创建对象
Object value = Class.forName(beanPath).newInstance();
//*****把key和value存入容器中
beans.put(key, value);
}
} catch (Exception e) {
throw new ExceptionInInitializerError("初始化properties失败");
}
}
/**
* *****
* @Description: 根据Bean的名称获取bean对象:改造(变成单例模式)
* @author EdPeng
* @date 2020/2/24 下午 11:23
*/
public static Object getBean(String beanName) {
return beans.get(beanName);
}
/**
* @param
* @return
* @throws
* @Description: 根据Bean的名称获取bean对象
* @author EdPeng
* @date 2020/2/23 下午 6:06
public static Object getBean(String beanName) {
Object bean = null;
try {
String beanPath = props.getProperty((beanName));
//通过反射来创建对象
bean = Class.forName(beanPath).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}*/
}
从代码中可以看到Spring中一种先进的思想:即被动接受的方式获得对象,这就叫控制反转(IOC),它是Spring框架的核心之一。包括依赖注入和依赖查找。IOC的作用就是:削减计算机程序的耦合(解除代码中的依赖关系。)
最后,修改业务层调用即可。
public class IAccountServiceImpl implements IAccountService {
//放弃自主寻找Dao的权利,把权利交给工厂类
// private IAccountDao accountDao = new AccountDaoImpl();
private IAccountDao accountDao = (IAccountDao) BeanFactory.getBean("accountDao");
private int i = 1;
@Override
public void saveAccount() {
accountDao.saveAccount();
System.out.println(i);
i++;
}
}
运行:
9.0 使用spring前,下载jar包并做介绍。
首先,下载Sping的开发包,目前Spring的官网下载东西很难下,所以这里就不留链接了,自行百度。
目前我用的是这个版本(spring-framework-5.0.2.RELEASE-dist.zip):
解压缩:
我的一般习惯:
打开,在浏览器中收藏:
或者采用谷歌浏览器,如下就是它为什么是全球最火的浏览器的原因之一:
当然,使用Spring目的就是取代上面案例中的BeanFactory工厂类。
10.0 spring中基于XML的IOC环境搭建
看图说话(IDEA软件):
首先修改pom.xml文件,设置打包格式为jar包:
<?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>com.edp</groupId>
<artifactId>first_project_spring</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
</project>
把上面案例中的代码,从com目录开始拷贝到新项目下:
修改基本结构和代码:
Client.java
public class Client {
public static void main(String[] args) {
IAccountService accountService = new IAccountServiceImpl();
accountService.saveAccount();
}
}
IAccountServiceImpl .java
public class IAccountServiceImpl implements IAccountService {
private IAccountDao accountDao = new AccountDaoImpl();
public void saveAccount() {
accountDao.saveAccount();
}
}
AccountDaoImpl .java
public class AccountDaoImpl implements IAccountDao {
public void saveAccount() {
System.out.println("保存了账户。");
}
}
当前,整个项目是不报错的。设置Maven配置:
配置Spring的配置,修改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>com.edp</groupId>
<artifactId>first_project_spring</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
</project>
稍等一会,包就导入了(左下角有个import package的话记得点击一下),maven为我们自动搭建环境:
我们也可以看到依赖关系:
说白了Spring就是一个Map,Map里面封装这我们要用的对象。
创建一个xml文件:
原则上命名只要不带中文即可。(有一个固定的名称,但现在不重要。)
在bean.xml文件中配置约束,在上面说的API的html文档中寻找:
约束如下:
<?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.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">
<!-- 把对象的创建交给spring来管理-->
<!-- id:获取时的唯一标志-->
<!-- class:反射要创建的权限定位名称-->
<bean id="accountService" class="com.edp.service.impl.IAccountServiceImpl"></bean>
<bean id="accountDao" class="com.edp.dao.impl.AccountDaoImpl"></bean>
</beans>
这就是依赖注入(Dependency Injection)的配置文件。
11.0 修改启动类
既然配置文件都改用spring的配置文件,当然启动类也需要改为spring的启动方式。
修改Client.java
package com.edp.ui;
import com.edp.service.IAccountService;
import com.edp.service.impl.IAccountServiceImpl;
import org.springframework.context.ApplicationContext;
public class Client {
/**
* @Description: 获取spring的Ioc核心容器,并根据id获取对象
* @author EdPeng
* @date 2020/2/26 上午 12:09
*/
public static void main(String[] args) {
//1.获取核心容器
ApplicationContext applicationContext = null;
}
}
查看ApplicationContext的源代码,可以找到这个借口抽象类和实现类,抽象类自然是没法继承和实现,那么我们可以看到下图框起来的3个实现类:
先用第一个(ClassPathXmlApplicationContext):
public class Client {
/**
* @Description: 获取spring的Ioc核心容器,并根据id获取对象
* @param
* @return
* @throws
* @author EdPeng
* @date 2020/2/26 上午 12:09
*/
public static void main(String[] args) {
//1.获取核心容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取bean对象
IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");
IAccountDao accountDao = applicationContext.getBean("accountDao",IAccountDao.class);
System.out.println(accountService);
System.out.println(accountDao);
}
运行:
所以我们只需要创建一个配置文件,把应该配置的信息交给spring,然后使用一个对象得到核心容器,再根据唯一对象取出想用的对象。
11.0 ApplicationContext的3个常用实现类
打开ApplicationContext的继承关系视图:
可以看到ApplicationContext还不是“老大”,BeanFactory才是。查看ApplicationContext的实现类:
注意看最前面的图标,“I”表示接口,两边带灰色的是抽象来,正常的“C”就是普通类。
三个常用实现类分别是:
- ClassPathXmlApplicationContext 可以加载类路径下的配置文件
- FileSystemXmlApplicationContext 可以加载磁盘任意路径下的配置文件(前提是必须有访问权限)
- AnnotationConfigApplicationContext 用于读取注解创建容器
以上Spring代码就是对ClassPathXmlApplicationContext的演示。FileSystemXmlApplicationContext可以依据原理类推:
ApplicationContext applicationContext =
new FileSystemXmlApplicationContext("F:\\acm\\workspace\\first_project_spring\\src\\main\\resources\\bean.xml");
AnnotationConfigApplicationContext类内容丰富有点大,会有一个专章节来介绍。
11.0 核心容器的两个接口引发出的问题:
- ApplicationContext 在构建核心容器时,创建对象采取的策略是采用立即加载的方式。只要读取完配置文件马上创建配置文件中配置的对象。
- BeanFactory 在构建核心容器时,创建对象采取的策略是延迟加载的方式。什么时候根据id获取对象,什么时候才真正的创建对象。
什么时候适合立即加载的方式,什么时候适合延迟加载的方式?
- ApplicationContext 单例模式适用
- BeanFactory 多例对象适用
在实际开发中,更多的采用ApplicationContext接口定义容器对象。
END