什么是Spring
一、Spring的优势
二、Spring的体系结构
先说一下从什么位置去下载Spring的源码
进入Spring官网,找到Spring Framework框架
点进去之后,找到如下位置,继续点击
进去之后,继续下拉,找到下面这个位置点进去
进去之后继续点击
找到上面这个位置之后,就按照层级目录,继续点下去
然后你就可以下载你想要的版本了
具体的体系结构
Ioc的概念和作用
一、分析一下程序之间的耦合性
首先我们来创建一个maven项目,然后里面写一个Jdbc的连接程序,它需要一个mysql的连接jar包
导入到pom.xml里面
pom.xml
上面程序的运行成功依赖于com.mysql.jdbc.Driver()这个对象 ,这个就是耦合,上面如果没有引入mysql的jar包,就会编译期给我们报错
耦合:程序间的依赖关系,这里面就包括了类之间的依赖与方法之间的依赖
解耦:降低程序之间的依赖关系
在实际开发中:编译期不依赖,运行时才依赖
上面代码我们就可以做出一些修改
那么解耦的思路:
第一步:使用户反射来创建对象,而避免使用new关键字
第二步:通过读取配置文件来获取要创建的对象全限定类名
二、曾经代码中的问题分析
首先我们来看一个模拟的账户查询业务代码
先来看一下dao层
做了一很简单的事儿,就死调用了数据库保存了账户信息
下面进入到service层里面看一下
下面在进入到业务层里面
上面这种各个文件的依赖关系啊,会让程序的耦合性非常差,其实就是太依赖了嘛
先来看一下依赖的这两个对象
你说这两个对象是不是都可以通过工厂模式来创建
所以我们来创建一个工厂来产生这两个对象的,我们都知道,工厂模式,是利用反射来创建对象的,下面来具体说一下如何创建
先来说一下实现原理
先来做这个配置文件
下面就是在工厂里面引入配置文件,然后把对象封装到集合里面,然后每次根据传入的key,来获取响应的对象
BeanFactory.java
package com.pxx.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;
/**
* 一个创建Bean对象的工厂
* Bean:在计算机里面就是组件的意思
* JavaBean: 用java写的可重用组件 一般理解为一个实体类
* 但是JavaBean的概念大于了实体类
*
* 下面说一下创建servicea对象和dao对象的核心步骤
* 1.需要一个配置文件来配置service和dao的全限定类名,这里也就是说不要写死
* 2.通过读取配置文件的配置内容,反射创建对象
*
*/
public class BeanFactory {
//这个后面引入配置文件信息
private static Properties prop;
//把对象引入到一个map集合里面
private static Map<String,Object> objectMap;
static {
try {
//上面两个属性必须new出来
prop = new Properties();
objectMap = new HashMap<String, Object>();
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
//信息加载到Properties类里面
prop.load(in);
//下面就是循环拿到key,利用value进行newInstance
Enumeration e = prop.keys();
while (e.hasMoreElements()) {
String key = (String) e.nextElement();//这个会拿到key
String value = prop.getProperty(key);//根据key来得到值
Object o = Class.forName(value).newInstance();
//然后把对象添加到集合里面
objectMap.put(key, o);
}
} catch (Exception e) {
//如果出错,直接error,程序失败
throw new ExceptionInInitializerError("初始化失败");
}
}
//需要根据配置文件的参数来获得相应对象
//name-》{accountService,accountDao}
public Object getObject(String name) {
//集合里面封装了两个对象
return objectMap.get(name);
}
}
现在我们去修改业务层的调用
然后去修改表现层的代码
运行结果:
分析一下上面的代码,一定是单例设计
一张图来直接说明
单例设计的有点就在于,内存不会开辟那么多的对象,提高效率
下面来说一下Ioc的概念与作用
根据上面的代码,之前我们是这样来生产一个对象
也就是说应用层与对象直接打交道。但是它现在放弃了这种方式,按照如下方式来创建了一个对象
把创建对象的工作交给了框架
这种被动接收的方式获取对象的思想就是控制反转,它是Spring框架的核心之一
使用Spring的IOC解决程序耦合
先来说一下Spring的开发包
进入到dist里面
特别说明:
我们用的是Spring5.0的版本
可以从这个位置去查询一些相关信息
下面我们来实现Account账户的解耦。
1.导入需要的spring的jar包,然后整一个xml文档,这个名字只要是英文就行
这个spring的相关jar包就做出来了,看一下右边
这个xml文档约束,就可以去
点进去这个位置去找
直接复制引入
然后去到表现层里面
运行结果:
下面来说一下ApplicationContext这个类
看一下结构
右键选择它的实现类
我们用到的就是下面这个实现类
我们直接拿一张图放过来
BeanFactory 和 和 ApplicationContext 的区别
ApplicationContext接口实现类:
spring中利用BeanFactory来实现对象的创建:
这个对象的创建内部需要传入一个资源文件对象
IOC中bean 标签和管理对象细节
一、创建Bean的三种方式
第一种:通过默认构造函数创建对象
第二种: 使用普通工厂的方法创建对象(使用某个类中的方法创建对象,存入spring容器)
也就是调用下面类中的方法创建一个对象
其实得到IAccountService的对象方法没有做啥改动 ,只是内部获取对象的方式发生了变化
第三种使用工厂当中的某个静态方法获取对象(使用某个类中的静态方法创建对象)
先来创建这个类与方法
三、bean的作用范围与生命周期
这里主要来演示一下单例和多例
说一下先在AccountServiceImpl里面做一个默认的构造函数,创建对象的时候会被调用,默认调用无参构造
这里说一下我这配置的域是单例的,单例在什么时候创建对象
我们在下面设置一个断点
debug一运行,你看对象无参构造已经被调用了
所以单例是在加载配置文件的时候就会被调用起来
Spring依赖注入
一、什么是依赖注入
二、依赖 注入的方式
构造函数注入
把AccountDaoImpl.java做一些修改,这只是一个模拟过程,不代表实际业务
上面就展示了通过构造函数需要封装的数据,下面是一个封装结果
上面就通过构造函数注入好了,下面来测试一下,很明显就是被调起来了嘛
set注入
这里必须说一下set注入原理
然后在说一下它的使用方法
在使用set方法注入之前,一定要生成set方法
假如说这里我们把无参构造给注释起来
然后再去看一下 bean.xml里面的set配置
客户端也看一下
然后调一下
报一堆错,这个其实就是说,没有去实例化一个AccountDaoImpl.java的一个对象,因为你把无参给注释掉了
现在打开
下面就来说复杂类型的注入与集合类型的注入
先来看一下AccountDaoImpl1.java
package com.pxx.dao.impl;
import com.pxx.dao.IAccountDao;
import java.util.*;
public class AccountDaoImpl1 implements IAccountDao {
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties myProps;
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setMyProps(Properties myProps) {
this.myProps = myProps;
}
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);
}
}
去bean.xml里面配置一下
运行结果:
这里上一下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中的依赖注入
依赖注入:
Dependency Injection
IOC的作用:
降低程序间的耦合(依赖关系)
依赖关系的管理:
以后都交给spring来维护
在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明
依赖关系的维护:
就称之为依赖注入。
依赖注入:
能注入的数据:有三类
基本类型和String
其他bean类型(在配置文件中或者注解配置过的bean)
复杂类型/集合类型
注入的方式:有三种
第一种:使用构造函数提供
第二种:使用set方法提供
第三种:使用注解提供(明天的内容)
-->
<!--构造函数注入:
使用的标签:constructor-arg
标签出现的位置:bean标签的内部
标签中的属性
type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始
name:用于指定给构造函数中指定名称的参数赋值 常用的
=============以上三个用于指定给构造函数中哪个参数赋值===============================
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
优势:
在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。
弊端:
改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。
-->
<bean id="now" class="java.util.Date"></bean>
<bean id="accountDao" class="com.pxx.dao.impl.AccountDaoImpl">
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="age" value="25"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<!--
采用set方法注入
-->
<bean id="accountDao1" class="com.pxx.dao.impl.AccountDaoImpl">
<property name="name" value="纠结伦"></property>
<property name="age" value="21"></property>
<property name="birthday" ref="now"></property>
</bean>
<!--
复杂类型的注入、集合类型注入
-->
<bean id="accountDao2" class="com.pxx.dao.impl.AccountDaoImpl1">
<property name="myStrs">
<set>
<value>张三</value>
<value>王五</value>
<value>李四</value>
</set>
</property>
<property name="myList">
<array>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</array>
</property>
<property name="mySet">
<list>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</list>
</property>
<!--下面
是map集合和Properties的对象自动注入
-->
<property name="myMap">
<props>
<prop key="map1">map1</prop>
<prop key="map2">map2</prop>
</props>
</property>
<property name="myProps">
<map>
<entry key="myProps1" value="张三"></entry>
<entry key="myProps2" value="李四"></entry>
</map>
</property>
</bean>
</beans>
这里的代码在spring1_copy_normal。