文章目录
Spring
第1章 Spring 概述
1.1 spring
Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架,以 IOC(Inverse Of Control:反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 SpringMVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架
1.2 Spring
- 1997 年 IBM提出了EJB 的思想
- 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 雏形)
- Rod Johnson ( spring 之父)
- 2017 年 9 9 月份发布了 g spring 的最新版本 0 spring 5.0 通用版( GA )
- spring是一个历史性的发展,这个版本有比较的大改动,与以往的spring有比较的大的改动
1.3 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 技术的最佳实践的范例。
1.4 spring 的体系结构
无论持久层的数据库还是事务、AOP及消息机制、web相关的内容、test单元测试这些都离不开核心容器IOC的支持(都需要导入IOC的包和dtd依赖)
1.5 三层架构的spring位置
- spring负责管理项目中的所有对象
- 可以将Spring看做项目中对象的管家
1.6 Spring一站式框架
- spring框架属于容器性质,容器中装什么对象就有什么功能,不仅不排斥其他框架,还能帮助其他框架管理对象
- aop支持
- ioc思想
spring jdbc
junit
测试支持
1.7 Spring 环境的搭建
(1) 在普通的工程中:
-
要导的包(4+2)
-
4个包(spring解压后libs)
spring-beans-4.3.9.RELEASE.jar
spring-context-4.3.9.RELEASE.jar
spring-core-4.3.9.RELEASE.jar
spring-expression-4.3.9.RELEASE.jar
-
2个包日志包(整合包中)
com.springsource.org.apache.commons.logging-1.1.1.jar
com.springsource.org.apache.log4j-1.2.15.jar
(2) 在maven工程中:
- 导入相应的指标:
在spring官网上,已经给出spring的开发包的坐标,也可以去下开发包
第二章 耦合和解耦以及IOC概念
2.1 什么是程序的耦合和解耦
- 耦合:程序间的依赖关系
- 包含:
- 类之间的依赖
- 方法间的依赖
- 包含:
- 解耦:
- 降低程序之间的依赖关系
- 依赖关系不可能没有,只可能降低
- 我们在开发中,有些依赖关系是必须的,有些依赖关系可以通过优化代码来解除的
- 解耦的思路:
- 第一步:使用反射创建对象,而避免使用new关键字来创建对象
- 第二步:通过读取配置文件来获取要创建的对象的全限定类名
- 实际开发时应该做到哪些??
编译时不依赖、运行时才依赖
2.2分析代码中存在的耦合度的问题
-
各个包之间的关系
-
实体类(要保存到数据库中的实体类)
(只是模拟一下,没有具体写)
//实体类 public class Account { }
-
持久层
-
持久层的接口
//账户的持久层继承接口 public interface IAccountDao { //模拟保存账户的操作 void saveAccount(Account account); }
-
持久成实现类
//账户的持久层实现类 public class AccountDaoImpl implements IAccountDao { public void saveAccount(Account account) { System.out.println("成功保存账户"); } }
-
-
业务层
-
业务层接口
//业务层的接口 public interface IAccountService { //模拟保存Account账户 void saveAccount(Account account); }
-
业务层实现类
//账户的业务成实现类:业务成接口的实现类 public class AccountServiceImpl implements IAccountService { //在业务层new出持久成的的实现类,调用相应的方法 //在这就出现了代码的耦合(应为是new出来的) private IAccountDao accountDao = new AccountDaoImpl(); public void saveAccount(Account account) { accountDao.saveAccount(account); } }
-
-
表现层
//模拟一个表现层,用于调用业务层 public class Client { public static void main(String[] args) { //在表现层是new出业务层的实体类,调用的相应的方法 //在这就出现了代码的耦合(应为是new出来的) IAccountService iAccountService = new AccountServiceImpl(); iAccountService.saveAccount(new Account()); } }
我们可以发现在 业务层调用持久成 表现成调用业务层的时候 都使用的是new的方法来获取业务层和持久层的数据-------》这就体现了代码耦合
2.3怎么解决上面代码中的耦合问题—工厂模式解耦
-
什么方式可以解决在使用业务层使用持久层、表现层使用业务层的时候不用new关键字???
-
回顾一下解耦的步骤:
- 第一步:使用反射创建对象,而避免使用new关键字来创建对象
- 第二步:通过读取配置文件来获取要创建的对象的全限定类名
-
使用工厂模式解耦:
-
创建Bean对象的工厂: Bean 在计算机英语里面,有可重用组件的含义(一个东西可以被多次的使用) javaBean: 用java语言编写的可重用组件 JavaBean > 实体类 他是干什么的?? 他就是创建我们service业务层和dao持久成对象的 如何创建呢?? 第一步:需要一个配置文件来配置我们的service和dao 配置的内容: 唯一标志 = 全限定类名 (key=value的形式) (使用xml文件或者properties文件) 第二步:通过读取配置文件中的内容,反射创建service和dao的对象来使用
-
-
配置文件:
-
配置文件存放了,service实现类和Dao实现类的全限定类名
accountService=com.zy.service.impl.AccountServiceImpl accountDao=com.zy.dao.Impl.AccountDaoImpl
-
-
javaBean工厂
public class BeanFactory { //定义一个配置文件对象 private static Properties properties; static { try { //实例化对象 properties = new Properties(); //好的properties文件的流对象 InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"); properties.load(in); } catch (IOException e) { throw new ExceptionInInitializerError("初始化bean.properties错误"); } } public static Object getBean(String beanName){ Object bean = null; try { String beanPath = properties.getProperty(beanName); //通过传入的key键,得到配置文件中的全限定类名,通过newInstance方法创建对象 bean = Class.forName(beanPath).newInstance(); } catch (Exception e) { e.printStackTrace(); } return bean; } }
-
实体类(要保存到数据库中的实体类)
(只是模拟一下,没有具体写)
//实体类 public class Account { }
-
持久层
-
持久层的接口
//账户的持久层继承接口 public interface IAccountDao { //模拟保存账户的操作 void saveAccount(Account account); }
-
持久成实现类
//账户的持久层实现类 public class AccountDaoImpl implements IAccountDao { public void saveAccount(Account account) { System.out.println("成功保存账户"); } }
-
-
业务层
-
业务层接口
//业务层的接口 public interface IAccountService { //模拟保存Account账户 void saveAccount(Account account); }
-
业务层实现类
//账户的业务成实现类:业务成接口的实现类 public class AccountServiceImpl implements IAccountService { //在业务层new出持久成的的实现类,调用相应的方法 //在这就出现了代码的耦合(应为是new出来的) //private IAccountDao accountDao = new AccountDaoImpl(); //使用工厂创建持久层对象 private IAccountDao accountDao = (IAccountDao) BeanFactory.getBean("accountDao"); public void saveAccount(Account account) { accountDao.saveAccount(account); } }
-
-
表现层
//模拟一个表现层,用于调用业务层 public class Client { public static void main(String[] args) { //在表现层是new出业务层的实体类,调用的相应的方法 //在这就出现了代码的耦合(应为是new出来的) //IAccountService iAccountService = new AccountServiceImpl(); //使用工厂创建业务层对象 IAccountService iAccountService = (IAccountService) BeanFactory.getBean("accountService"); iAccountService.saveAccount(new Account()); } }
2.4工厂模式解耦升级版
分析上面的版本有什么缺陷??
当多次在使用表现层调的时候:
要多次通过表现层多次访问业务层,业务层访问持久层,这之间多次的访问解析了配置文件,
创建了多个对象,效率比较慢
我们要实现什么,怎么进行优化??
多次的 表现层多次访问业务层,业务层访问持久层 使用同一个对象
在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,
让一个类中的方法通过读取配置文件,把这些对象创建出来 并存起来。
在接下来的使用的时候,直接拿过来用就好了。
那么,这个读取配置文件,创建和获取三层对象的类就是工厂。
public class BeanFactory {
//定义一个配置文件对象
private static Properties properties;
//定义一个容器,放service和dao的实例化对象
private static Map<String,Object> beanMap;
static {
try {
//实例化对象
properties = new Properties();
//好的properties文件的流对象
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
properties.load(in);
//实例化容器
beanMap = new HashMap<String,Object>();
//枚举取出配置文件中的所有key
Enumeration kets = properties.keys();
//遍历枚举key得到value,创建对象放到beanMap中
while (kets.hasMoreElements()) {
try {
//得到key键
String key = kets.nextElement().toString();
//得到配置文件中的全限定类名
String beanpath = properties.getProperty(key);
//反射创建对象
Object value = Class.forName(beanpath).newInstance();
//容器中放入相同的key键和创建好的对象
beanMap.put(key, value);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (IOException e) {
throw new ExceptionInInitializerError("初始化bean.properties错误");
}
}
public static Object getBean(String beanName){
// Object bean = null;
// try {
// String beanPath = properties.getProperty(beanName);
// bean = Class.forName(beanPath).newInstance();
// } catch (Exception e) {
// e.printStackTrace();
// }
//直接返回容器中的对象
return beanMap.get(beanName);
}
}
2.5 反转控制( IOC )的概念和作用
1 、对象存哪去?
- 分析:
- 由于我们是很多对象,肯定要找个集合来存。这时候有 Map 和 List 供选择。
- 到底选 Map 还是 List 就看我们有没有查找需求。
- 有查找需求,选 Map。所以我们的答案就是
- 在应用加载时,创建一个 Map,用于存放三层对象。
我们把这个 map 称之为 容器。
2、还是没解释什么是工厂?
-
工厂就是负责给我们从容器中获取指定对象的类。这时候我们获取对象的方式发生了改变。
-
以前: 我们在获取对象时,都是采用 new 的方式。是主动的。
- 现在:我们获取对象时,同时跟工厂要,有工厂为我们查找或者创建对象。是被动的。
3 为什么叫 反转控制 IOC ??
- 为什么在使用工厂解耦时候,不叫降低依赖叫降低解耦呢??
- 原来使用new的方法主动的创建一个对象,现在使用工厂的方式放到容器中实现解耦
- 把创建对象的控制权利交给了框架
4 明确IOC的作用:
- 削减计算机程序的耦合(降低我们代码中的依赖关系)。