Spring学习一-Spring概述、初识 IOC
1、Spring概述
1.1、Spring 是什么
Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control: 反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 Spring MVC 和持久层 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 雏形)
- 2017年9月份发布了spring的最新版本spring 5.0通用版(GA)
1.3、Spring 的优势
- 方便解耦,简化开发
- AOP 编程的支持
- 声明式事务的支持
- 方便程序的测试
- 方便集成各种优秀框架
- 降低 JavaEE API 的使用难度
- Java 源码是经典学习范例
1.4、体系结构
2、IOC 的概念和作用
2.1、耦合性
耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调 用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关 系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。
2.2、如何解决耦合性的思路
之前学习 jdbc 时,是通过反射来注册驱动的,代码如下:
Class.forName("com.mysql.jdbc.Driver");//此处只是一个字符串
这里使用了反射,在编译阶段可以正常编译成功,不会因为类中没有依赖驱动类而报错,但是这样又是一种硬编码的写法,在类中使用了常量。为了解决这个问题,可以将常量写入到配置文件中。
2.3、使用工厂模式进行解耦
- 当应用启动时,就加载配置文件,读取配置
- 根据配置,使用反射创建对象实例
- 使用对象
2.4、控制反转
之前我们使用对象,哪里需要就在哪里创建,使用new;现在我们将对象的创建后放入到 map 中进行存储,即容器中。
2.4.1、配置文件
beans.properties
userService=com.wmding.mybean.service.impl.UserServiceImpl
helloSpring=com.wmding.HelloSpring
2.4.2、工厂
BeanFactory.java
package com.wmding.mybean.factory;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* @author 明月
* @version 1.0
* @date 2020-04-19 20:53
* @description:
*/
public class BeanFactory {
private static Properties properties;
private static Map<String, Object> beans;
static {
properties = new Properties();
try {
beans = new HashMap<String, Object>();
properties.load(BeanFactory.class.getClassLoader().getResourceAsStream("beans.properties"));
Enumeration<Object> keys = properties.keys();
while (keys.hasMoreElements()) {
String key = keys.nextElement().toString();
String value = properties.getProperty(key);
Object o = Class.forName(value).newInstance();
beans.put(key, o);
}
} catch (Exception e) {
throw new ExceptionInInitializerError("初始化错误");
}
}
public static Object getBean(String classPath) {
return beans.get(classPath);
}
}
2.4.3、使用
public class Client {
public static void main(String[] args) {
//Test01();
UserService userService = (UserService) BeanFactory.getBean("userService");
userService.saveUser(new User("w", 99));
}
private static void Test01() {
UserService userService = null;
try {
userService = (UserService) Class.forName("com.wmding.mybean.service.impl.UserServiceImpl").newInstance();
} catch (Exception e) {
e.printStackTrace();
}
userService.saveUser(new User("wmding", 23));
}
}
之前获取对象是主动的,现在获取对象是从工厂要(工厂帮我们创建并保存到map容器中)是被动的。
这种被动的接收的方式获取对象的思想就是控制反转,就是 spring 框架的核心之一。
3、Spring 的 IOC 解决程序耦合
3.1、使用到的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
3.2、基于 XML 的配置创建 bean
beans.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">
<bean id="user" class="com.wmding.mybean.bean.User">
<property name="name" value="wmding"/>
<property name="age" value="20"/>
</bean>
</beans>
public class Client {
/**
* 获取 Spring 的 IOC 核心容器,并根据 id 获取对象
*
* ApplicationContext 的三个常用实现类
* ClassPathXmlApplicationContext:加载类路径下的配置文件,
* FileSystemXmlApplicationContext:加载磁盘下的任意路径下的配置文件,但是源码中会把路径的第一个/给去掉,导致在Mac,Linux下需要在路径开头多写一个/
* AnnotationConfigApplicationContext:它用于读取注解创建容器。
* @param args
*/
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//ApplicationContext applicationContext = new FileSystemXmlApplicationContext("/"+"/Users/wmding/WorkSpaces/My/spring/src/main/resources/beans.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
System.out.println(userService);
userService.saveUser(new User("111",11));
}
}
BeanFactory 和 ApplicationContext 的区别
BeanFactory 才是 Spring 容器中的顶层接口。 ApplicationContext 是它的子接口。
BeanFactory 和 ApplicationContext 的区别:
- 创建对象的时间点不一样。ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。 BeanFactory:什么使用什么时候创建对象。
3.3、IOC 中 bean 标签的使用
3.3.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、bean的作用范围和生命周期
- 单例对象:scope=“singleton”
生命周期:
对象出生:当应用加载,创建容器时,对象就被创建了。
对象活着:只要容器在,对象一直活着。
对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
- 多例对象:scope=“prototype”
生命周期:
对象出生:当使用对象时,创建新的对象实例。
对象活着:只要对象在使用中,就一直活着。
对象死亡:当对象长时间不用时,被 java 的垃圾回收器回收了。
3.3.3、实例化 bean 的三种方式
- 使用默认构造函数
- 静态工厂-使用静态工厂的方法创建对象
- 实例工厂-使用实例工厂的方法创建对象
3.3.3.1、使用默认构造函数
<!--
第一种方式,使用默认无参构造函数
会根据默认无参构造函数来创建类对象,如果 bean 中没有默认无参构造函数,将会失败
-->
<bean id="userService" class="com.wmding.mybean.service.impl.UserServiceImpl"/>
3.3.3.2、实例工厂
<!--
第二种方式,使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入Spring容器中)
-->
<bean id="beanFactory" class="com.wmding.ioc.factory.BeanFactory"/>
<bean id="userService" factory-bean="beanFactory" factory-method="getUserService"/>
public class BeanFactory {
public UserService getUserService() {
return new UserServiceImpl();
}
}
3.3.3.3、静态工厂
<!--
第三种方式,使用工厂中的静态方法创建对象(使用某个类的静态方法创建对象,并存入Spring的容器中)
-->
<bean id="userService" class="com.wmding.ioc.factory.StaticBeanFactory" factory-method="getUserService"/>
public class StaticBeanFactory {
public static UserService getUserService() {
return new UserServiceImpl();
}
}
3.4 Spring 的依赖注入
依赖注入:Dependency Injection。它是spring框架核心ioc的具体实现。
3.4.1、构造函数注入
<!--
需要类中有一个构造函数;
constructor-arg
属性:
index:指定参数在构造函数参数列表的索引位置
type:指定参数在构造函数中的数据类型
name:指定参数在构造函数中的名称
value:它能赋的值是基本数据类型和 String 类型
ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
-->
<bean id="user2" class="com.wmding.mybean.bean.User">
<constructor-arg name="name" value="wmding"></constructor-arg>
<constructor-arg name="age" value="20"></constructor-arg>
</bean>
3.4.2、set 方法注入
<!--
提供set方法;
property
属性:
name:找的是类中 set 方法后面的部分
ref:给属性赋值是其他 bean 类型的
value:给属性赋值是基本数据类型和 string 类型的
-->
<bean id="user" class="com.wmding.mybean.bean.User">
<property name="name" value="wmding"/>
<property name="age" value="20"/>
</bean>
3.4.3、注入集合属性
<bean id="user3" class="com.wmding.mybean.bean.User">
<property name="name" value="wmding"/>
<property name="age" value="20"/>
<property name="map">
<props>
<prop key="map1">map1</prop>
<prop key="map2">map3</prop>
</props>
</property>
<property name="list">
<list>
<value>111</value>
<value>222</value>
<value>333</value>
</list>
</property>
</bean>
下一篇: Spring源码学习之旅 初识IOC
推荐阅读
-
利用递归,反射,注解等,手写Spring Ioc和Di 底层(分分钟喷倒面试官)了解一下
-
Spring框架学习-Spring和IOC概述
-
[读书笔记] Spring MVC 学习指南 -- 第一章
-
Spring概述学习笔记
-
MVC使用Spring.Net应用IOC(依赖倒置)学习笔记3
-
Spring的学习一(Spring的介绍,搭建第一个Spring程序)
-
Spring入门(一)— IOC、DI
-
Spring 框架学习第三节:核心理念之一 —— IoC(控制反转)
-
一起学习Spring boot 2.1.X | 第五篇:Mybatis Druid 数据库(注解版)
-
Spring源码学习(一):Spring容器创建和初始化工作准备