一、概述
Spring是一个轻量级开源框架
两大核心
- 控制反转(IoC)
- 面向切面编程(AOP)
1.1Spring的优势
- 方便解耦:提供IoC容器管理对象,避免程序过度耦合
- AOP编程支持:方便进行面向切面的编程
- 声明式事务的支持:从单调烦闷的事务代码中解脱,通过声明方式对事务进行管理,提高开发效率和质量
- 集成各种框架:Spring 整合各种框架,降低框架的使用难度
- 方便测试:简化测试的代码
- 源码学习:Spring 的源代码设计精妙,对 Java 设计模式灵活运用,是 Java 技术的最佳实践的范例
MVC架构图:
Spring可以用于表现层、业务层、持久层
1.2 耦合
1.2.1什么是耦合
程序的耦合:程序间的依赖关系
包括:
-
类之间的依赖
-
方法间的依赖
解耦:
-
降低程序间的依赖关系
-
编译期不依赖,运行时才依赖
解耦的思路:
-
第一步:使用反射来创建对象,而避免使用new关键字
-
第二步:通过读取配置文件来获取要创建的对象全限定类名
开发中力争做到高内聚低耦合
public static void main(String[] args) throws Exception {
//1、加载驱动
DriverManager.deregisterDriver(new com.mysql.cj.jdbc.Driver());
//2、获取连接
Connection connection =
DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/spring?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true"
, "root", "root123");
//3、获取操作表对象
String sql = "select `name` from `account`";
PreparedStatement ps = connection.prepareStatement(sql);
//4、执行SQL语句
ResultSet rs = ps.executeQuery();
//5、遍历结果集
while (rs.next()){
String name = (String) rs.getObject("name");
System.out.println(name);
}
//6、关闭资源
rs.close();
ps.close();
connection.close();
}
上述代码:
依赖了数据库的具体驱动类(MySQL),如果这时候更换了数据库品牌(比如 Oracle),需要修改源码来重新数据库驱动。若是没有这个驱动类,编程时就会报错,所以耦合很强
1.2.2 程序解耦的思路
解决耦合:
Class.forName("com.mysql.cj.jdbc.Driver");
使用反射来加载驱动。此时,需要的只是一个字符串,不再依赖一个具体的驱动类,就算删除 mysql 的驱动 jar 包,依然可以编译
1.2.3 工厂模式解耦
Class.forName(“com.mysql.cj.jdbc.Driver”)中驱动的全限定类名在程序中写死的,一旦要改还是要修改源码,引出工厂模式解决,通过读取配置文件路径读取驱动名,然后反射加载驱动
工厂模式:
在实际开发中,可以把三层的对象都使用配置文件配置起来,当程序运行时,让一个工具类通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。
那么,这个读取配置文件,创建和获取三层对象的工具类就是工厂
properties文件
accountService=com.json.service.AccountService
accountDao=com.json.dao.AccountDao
工厂模式创建对象
/*
* 一、需要一个配置文件来配置我们的service和dao
* 配置的内容:唯一标识=全限定类名(key=value)
* 二、通过读取配置文件中配置的内容,反射创建对象
*
* 配置文件可以是xml也可以是properties
*/
public class BeanFactories {
private static Properties properties ;
// 定义一个Map,用于存放我们要创建的对象。我们把它称之为容器
private static Map<String,Object> beans ;
static {
try {
properties = new Properties() ;
beans = new HashMap<String, Object>();
InputStream in = BeanFactories.class.getClassLoader().getResourceAsStream("bean.properties");
//加载properties配置文件
properties.load(in);
//取出配置文件中所有的Key
Enumeration<Object> keys = properties.keys();
while(keys.hasMoreElements()){
//取出每个Key
String beanName = (String) keys.nextElement();
//根据key获取value
String beanPath = properties.getProperty(beanName);
//反射创建对象
Object bean = Class.forName(beanPath).newInstance();
//把key和value存入容器中
beans.put(beanName, bean);
}
} catch (Exception e) {
throw new ExceptionInInitializerError("创建工厂失败");
}
}
//根据bean的名称获取对象
public static Object getBean(String beanName){
return beans.get(beanName);
}
}
模拟表现层
public class AccountController {
/**
* 模拟保存账号的表现层
* @param args
*/
public static void main(String[] args) {
AccountService accountService = (AccountService) BeanFactories.getBean("accountService");
accountService.save();
}
}
模拟业务层
public class AccountService {
private AccountDao accountDao = (AccountDao) BeanFactories.getBean("accountDao");
public void save(){
accountDao.saveAccount();
}
}
模拟持久层
public class AccountDao {
public void saveAccount(){
System.out.println("模拟保存账号");
}
}
如此,service、dao获取对象则不再依赖一个具体的类,而是通过唯一标识的字符串,通过反射创建对象
二、控制反转
由于需要存储很多对象,需要利用集合Map和List,选择Map或List在于是否有查找需求,有查找需求,选Map
在程序运行时,创建一个Map存放对象,称之为容器
获取对象的方式:
- 常规:获取对象时,都是采用new的方式,是主动的
- 控制反转:利用工厂从容器中获取指定的对象,这时获取对象的方式发生了改变,是被动的
这种被动的获取对象的思想就是控制反转
控制反转(Inversion of Control):
- 依赖注入(Dependency Injection)
- 依赖查找(Dependency Lookup)
IoC的作用:削减程序中的耦合(解除代码中的依赖关系)
三、IOC容器
基于XML的配置步骤开发
-
导入Spring的核心jar
-
创建XML文件(application.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来管理--> <bean id="accountDao" class="com.json.dao.AccountDao"></bean> <bean id="accountService" class="com.json.service.AccountService"></bean> </beans>
-
测试是否配置成功
public static void main(String[] args) { //ApplicationContext对象为上下文对象(可以认为该对象为IOC容器),用于连接xml配置文件与java代码 ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); //根据id获取Bean对象(方式一) AccountService accountService = (AccountService) context.getBean("accountService") ; //根据id获取Bean对象(方式二) AccountDao accountDao = context.getBean("accountDao",AccountDao.class); }
-
运行结果
g)]
3.1 ApplicationContext对象
一般称BeanFactory为IoC容器,而称ApplicationContext为应用上下文 ,ApplicationContext是连接xml配置文件与程序的对象
可以解析xml配置文件,获取IOC容器中的对象供程序使用
ApplicationContext的三个常用实现类:
- ClassPathXmlApplicationContext
- 加载类路径下的配置文件,要求配置文件必须在类路径下(推荐使用)
- FileSystemXmlApplicationContext
- 加载磁盘任意路径下的配置文件(必须有访问权限)
- AnnotationConfigApplicationContext:
- 用于读取注解(配置类)创建容器
3.2 BeanFactory对象
- BeanFactory和ApplicationContext是Spring的两大核心接口,而其中ApplicationContext是BeanFactory的子接口,它们都可以当做Spring的容器,Spring容器是生成Bean实例的工厂,并管理容器中的Bean
- 一般称BeanFactory为IOC容器,而称ApplicationContext为应用上下文
- BeanFactory是Spring最底层的接口,提供了最简单的容器的功能,只提供了实例化对象和获取对象的功能
BeanFactory与ApplicationContext的区别
BeanFactory | ApplicationContext | |
---|---|---|
功能 | 实例化对象、获取对象 | 国际化、访问资源,如URL和文件、消息发送、响应机制、AOP(拦截器)、实例化对象、获取对象 |
创建对象方 式 | 延迟加载(获取对象时才创建) | 立即加载(读取完配置文件马上就创建) |
单例/多例 | 多例对象 | 单例对象 |
public static void main(String[] args) {
//加载配置文件时,立即创建所有的Bean对象实例 ,且每个Bean对象默认是单例
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
AccountService accountService = (AccountService) context.getBean("accountService") ;
Resource resource = new ClassPathResource("application.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
//只要获取Bean时,才创建对应的Bean,且为多例
AccountDao accountDao = beanFactory.getBean("accountDao",AccountDao.class);
}
3.3 Bean
作用:用于配置对象让 Spring 来创建的。默认情况下调用无参构造函数。如果没有无参构造函数则不能创建成功
3.3.1 bean标签
属性:
- id:给对象在容器中提供一个唯一标识,用于获取对象
- class:类的全限定类名,用于反射创建对象。默认情况下调用无参构造函数
- scope:对象的生命周期
- singleton:默认值,单例(容器创建就创建Bean)
- prototype:原型,多例(具体获取时才创建Bean)
- request:Spring 创建一个 Bean 的对象,将对象存入到 request 域中
- session:创建一个 Bean 的对象,将对象存入到 session 域中
- global-session:创建一个 Bean 的对象,存放于Context域中
- init-method:指定类中的初始化时执行的方法
- destroy-method:指定类中的销毁时执行方法(销毁容器时才执行)
- lazy-init:懒加载(具体获取时才创建Bean)
创建、初始化、销毁
public class AccountService {
public AccountService(){
System