学习目标

1、Spring框架简介
2、IOC概念
3、IOC容器
4、IOC的XML配置案例
5、IOC的注解配置案例
6、IOC的实现原理

1、Spring框架简介

1.1 Spring基本概念

Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
  • 轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:Spring应用中的对象不依赖于Spring的特定类。

  • 控制反转——通过控制反转(IoC)技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。

  • 面向切面——分离应用的业务逻辑与系统级服务。应用对象只实现业务逻辑。它们并不负责其它的系统级关注点,例如日志或事务支持。

  • 容器——Spring是一种容器,能创建对象并管理对象的配置和生命周期。

  • 框架——Spring可以将第三方框架灵活的整合起来,完成各种JavaEE企业级项目开发。

    所有Spring的这些特征使我们能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。

1.2 Spring框架的组成

上面是Spring的主要组件:

  • Core 核心组件 ,提供IOC功能
  • Context 上下文组件,提供包的扫描、国际化、事件等功能
  • Beans JavaBean的管理
  • SpEL Spring表达式
  • AOP 面向切面编程
  • Test 集成单元测试
  • MVC SpringMVC框架
  • JDBC 集成JDBC开发
  • ORM 数据库开发
  • Cloud 微服务开发框架
  • Securty 权限控制框架

2、IOC的概念

2.1 什么是IOC

IOC(Inverse of Control)控制反转是一种程序设计思想。

控制是什么?

​ JavaBean(Java对象)的创建和管理

反转是什么?

​ 一般情况下对象的创建和管理由开发者控制,反转是把对象的创建和管理交给容器完成,然后再交给开发者。

2.2 IOC有什么用

IOC的主要作用是:解耦。

解耦,是降低程序耦合度,也就是减少程序代码之间的依赖性,如果代码之间的依赖性很高,修改一处代码会影响很多其他的代码,这就给项目的稳定性带来的问题,不利于代码的扩展和维护。

没有IOC的程序中,我们使用new来完成对象的创建,如果需要的对象的类型发生改变,就需要手动修改代码。

有了IOC后,对象的创建由第三方(Spring容器)完成,由Spring来管理应用中所有对象的生命周期,开发者只需要关注自己的业务逻辑,代码更利于扩展和维护。

2.3 什么是DI

DI(Dependency Injection)依赖注入,是IOC另一种说法,也就是对象由容器来管理,注入到我们需要依赖中。

生活中的DI:我们身体不生产疫苗,由医院生产,需要的使用再注射进来。

3、IOC容器

3.1 容器的概念

IOC容器是 Spring 框架的核心。容器将创建对象,配置对象,并管理对象的整个生命周期。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。

3.2 容器的分类

Spring的IOC容器分为两种:

1)BeanFactory

最简单的容器,给 DI 提供了基本的支持,它用 org.springframework.beans.factory.BeanFactory 接口来定义。BeanFactory 或者相关的接口,如 BeanFactoryAware,InitializingBean,DisposableBean,在 Spring 中仍然存在具有大量的与 Spring 整合的第三方框架的反向兼容性的目的。

2)ApplicationContext

继承了BeanFactory,添加了更多的企业特定的功能,例如从一个属性文件中解析文本信息的能力,发布应用程序事件给感兴趣的事件监听器的能力。该容器是由 org.springframework.context.ApplicationContext 接口定义。通常推荐使用 ApplicationContext。
ApplicationContext 接口的主要实现:
1) FileSystemXmlApplicationContext 文件绝对路径 D:\xx\xxx基于文件系统中XML文件配置的应用程序上下文
2) ClassPathXmlApplicationContext src  resources --> classpath文件相对路径基于ClassPath路径中XML文件配置的应用程序上下文
3) AnnotationConfigApplicationConext 基于注解配置的应用程序上下文

4、IOC的入门案例

4.1 案例概述

模拟电脑的装配,定义Cpu和Memory(内存)接口,Cpu接口有IntelCpu和AMDCpu两个实现类,Memory接口有KingstonMemory和SumsungMemory两个实现类,Computer类中定义了Cpu和Memory类型的两个属性

4.2 案例实现

  1. 创建Maven项目

  2. 导入依赖

<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.8.RELEASE</version>
</dependency>
  1. 编写代码
/*** CPU接口*/
public interface Cpu {void run();
}
public class AMDCpu implements Cpu {public void run() {System.out.println("AMD的CPU在运行。。。");}
}public class IntelCpu implements Cpu {public void run() {System.out.println("英特尔CPU在运行。。。");}
}
/*** 内存*/
public interface Memory {void read();void write();
}
public class KingstonMemory implements Memory {public void read() {System.out.println("金士顿内存读取数据");}public void write() {System.out.println("金士顿内存写入数据");}
}public class SumsungMemory implements Memory {public void read() {System.out.println("三星内存读取数据");}public void write() {System.out.println("三星内存写入数据");}
}
/*** 电脑*/
public class Computer {private String brand;private Cpu cpu;private Memory memory;public Cpu getCpu() {return cpu;}public void setCpu(Cpu cpu) {this.cpu = cpu;}public Memory getMemory() {return memory;}public void setMemory(Memory memory) {this.memory = memory;}public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public void start(){System.out.println(brand + "电脑启动了!");cpu.run();memory.read();memory.write();}
}
  1. 添加Spring配置文件

在resources目录下,添加Spring配置文件

<?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="cpu" class="com.blb.ioc_demo.AMDCpu"></bean><bean id="memory" class="com.blb.ioc_demo.KingstonMemory"></bean><!--Java对象配置--><bean id="computer" class="com.blb.ioc_demo.Computer"><property name="brand" value="联想"></property><property name="cpu" ref="cpu"></property><property name="memory" ref="memory"></property></bean>
</beans>
  1. 测试代码
public class TestComputerSpring {public static void main(String[] args) {//创建应用程序上下文ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");//获得对象Computer computer = (Computer) context.getBean("computer");computer.start();}
}

4.3 知识点讲解

4.3.1 beans 节点

​ beans节点是Spring配置文件的根节点,所有Javabean都定义在beans内部

4.3.2 bean 节点

​ 代表一个javabean对象
​ bean节点的属性

  • id 对象id,id不能重复

  • name 对象名称,name可以重复,如果重复将读取最后一个

  • class 对象的类型,包名+类名

  • scope 作用域

    • singleton

      单例模式,在IOC容器中仅存在一个实例

    • prototype

      多例,每次从IOC容器调用Bean时,都会返回一个新的实例

    • request

      每次Http请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境

    • session

      同一个会话共享一个Bean,不同的会话使用不同的Bean,仅适用于WebApplicationContext环境

    • application

      一般用于portlet应用环境,仅适用于WebApplicationContext环境

4.3.3 property 节点

​ 用来配置javabean的属性依赖

​ property节点的属性

  • name 属性的名称

  • ref 注入引用类型的对象,值就是前面定义bean的id

  • value 注入基本数据类型和String类型的值,如给brand的值注入“联想”

4.3.4 属性注入的几种方式

​ 注入属性有几种方式:

​ 1) set方法注入,就是上面通过property进行配置

​ 2) 构造方法注入

​ 给Computer类添加带参数的构造方法,将property改为:

<constructor-arg name="brand" value="苹果"></constructor-arg>
<constructor-arg name="cpu" ref="cpu"></constructor-arg>
<constructor-arg name="memory" ref="memory"></constructor-arg>

​ 3) 自动装配

​ 可以通过bean的autowire属性配置

​ 类型:

  • no 默认,不自动装配

  • byType 通过类型查找对象,如果相同类型的对象有多个,会出现异常

  • byName 通过名称查找对象,如果找不到对应的id或name的对象,会出现空指针异常

  • constructor 通过构造方法装配

4.3.5 ClassPathXmlApplicationContext

​ 通过ClassPath路径查找XML配置文件的IOC容器

  • 创建方式
new ClassPathXmlApplicationContext("spring.xml");
注意:src和resources都在ClassPath下,所以可以直接写文件名,如果文件不在ClassPath下,则会出现异常
  • getBean方法

​ 用于在配置文件中查找对象,创建对象,返回对象

Object getBean(Class)    通过对象的类型查找Object getBean(String) 通过对象id或name查找

5、注解配置的IOC案例

5.1 Spring的重要的注解

  • @Component 组件,被标记的类会被Spring扫描到,交给Spring容器进行管理
  • @ComponentScan 组件扫描,标记在配置类上,用于扫描某一个包下带@Component的类
  • @Configuration 配置类,标记在类上,该类作为配置类代替XML
  • @Value 注入值类型数据,配置属性或set方法上
  • @Autowrie 自动装配,默认按类型进行注入
  • @Qualifier 标记名称,配置在类和注入属性上,用于区分类型相同的对象
  • @Resource 自动装配,类似Autowired,默认按名称注入,名称没有再按类型注入
  • @Repository 类似@Component,标记DAO实现类
  • @Service 类似@Component,标记Service实现类
  • @Controller 类似@Component,标记Controller类

@Autowire和@Resource的区别

1) @Autowire按类型注入;@Resource默认按名称注入,名称没有再按类型

​ @Resource不设置名称,默认按属性名查找,指定名称 @Resource(name=“名称”)

2) @Autowire是Spring提供的;@Resource是JAVAEE的

BeanFactory和FactoryBean的区别

BeanFactory是Spring的顶层IOC容器,用于创建和管理对象

FactoryBean是一种JavaBean,提供创建对象的方法,在定义对象时使用factory-bean和factory-method指定对象的创建方式

/*** 工厂对象,提供组件的创建方法*/
public class ComputerFactoryBean {public ICpu getAMDCpu(){return new AMDCpu();}public ICpu getIntelCpu(){return new IntelCpu();}public IMemory getKingstonMemory(){return new KingstonMemory();}public IMemory getSumsungMemory(){return new SumsungMemory();}
}
<bean id="factory" class="com.hopu.computer.ComputerFactoryBean"></bean><bean id="cpu" factory-bean="factory" factory-method="getIntelCpu"></bean>

bean的属性:init-method(初始化)、destroy-method(销毁)

5.2 注解实现IOC

修改上面的案例,给每个接口的一个实现类加上@Component注解

@Component
public class AMDCpu implements Cpu {public void run() {System.out.println("AMD的CPU在运行。。。");}
}@Component
public class KingstonMemory implements Memory {public void read() {System.out.println("金士顿内存读取数据");}public void write() {System.out.println("金士顿内存写入数据");}
}

给Computer类添加@Component注解,值类型属性用@Value注入,引用类型用@Autowired注入

@Component
public class Computer {@Value("戴尔")private String brand;@Autowiredprivate Cpu cpu;@Autowiredprivate Memory memory;
/*** 配置类*/
@ComponentScan(basePackages = "com.blb.ioc_demo")
@Configuration
public class ComputerConfig {public static void main(String[] args) {//创建注解应用程序上下文AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ComputerConfig.class);//获得对象Computer computer = context.getBean(Computer.class);computer.start();}
}

思考问题

如果给每个接口的所有实现类都加上@Component注解会出现什么问题?如何解决?

6、 IOC的实现原理

6.1 思考

思考问题1

上面案例中,配置了@Component注解后,Spring是怎么知道这个类上有这个注解的?

思考问题2

没有使用new关键字,Spring是如何创建对象的?

思考问题3

Spring是如何将创建的对象注入到对应的属性中的?

6.2 IOC实现原理

问题的答案是:通过自定义注解+反射机制实现

/*** 注入值的注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyValue {//注入的值String value();
}
/*** 注入对象的注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {//注入的类型Class value();
}
/*** 电脑*/
public class Computer {@MyValue("戴尔")private String brand;@MyComponent(IntelCpu.class)private Cpu cpu;@MyComponent(SumsungMemory.class)private Memory memory;...省略其余部分...
/*** 电脑工厂*/
public class ComputerFactory {/*** 创建电脑对象* @param computerClass* @return*/public Computer createComputer(Class computerClass) throws Exception {//反射创建对象Object computer = computerClass.newInstance();//遍历所有的属性Field[] fields = computerClass.getDeclaredFields();for(Field field : fields){String fName = field.getName();//读取自定义注解MyValue myValue = field.getDeclaredAnnotation(MyValue.class);if(myValue != null){//通过反射调用set方法注入值String mName = "set" + fName.substring(0,1).toUpperCase() + fName.substring(1);Method set = computerClass.getDeclaredMethod(mName, field.getType());set.invoke(computer,myValue.value());}MyComponent myComponent = field.getDeclaredAnnotation(MyComponent.class);if(myComponent != null){//通过反射调用set方法注入对象String mName = "set" + fName.substring(0,1).toUpperCase() + fName.substring(1);Method set = computerClass.getDeclaredMethod(mName, field.getType());//通过配置的类型创建对象Object obj = myComponent.value().newInstance();set.invoke(computer,obj);}}return (Computer) computer;}
}
public class TestFactory {public static void main(String[] args) {ComputerFactory factory = new ComputerFactory();try {Computer computer = factory.createComputer(Computer.class);computer.start();} catch (Exception e) {e.printStackTrace();}}
}

面试题:

  1. Spring是什么?
  2. Spring有哪些主要组件?
  3. 介绍一下IOC
  4. 介绍Spring的容器有哪些?
  5. @Autowired和@Resource的区别
  6. 自动装配有几种方式
  7. 属性注入有几种方式
  8. BeanFactory和FactoryBean的区别

01-Spring_快速入门相关推荐

  1. Bootstrap学习笔记01【快速入门、栅格布局】

    Java后端 学习路线 笔记汇总表[黑马程序员] Bootstrap学习笔记01[快速入门.栅格布局][day01] Bootstrap学习笔记02[全局CSS样式.组件和插件.案例_黑马旅游网][d ...

  2. docsify笔记 01:快速入门

    文章目录 目的 快速开始 多页文档与自定义侧边栏 自定义导航栏 设置封面 其它补充 docsify中的Markdown 加载 html / js / css 本地化使用 总结 目的 docsify 是 ...

  3. 01.MyBatis快速入门

    1.下载jar包 Mybatis包+数据库驱动包 https://github.com/mybatis/mybatis-3/releases 2.新建Java工程并导入jar包 3.创建数据库与表 C ...

  4. react 基础 - 01 (快速入门:脚本引入、JSX语法)

    1.脚本引入 1.1  建立挂载点    <div id="root"></div> 1.2 引入react相关库  <script src=&quo ...

  5. Servlet和HTTP请求协议-学习笔记01【Servlet_快速入门-生命周期方法、Servlet_3.0注解配置、IDEA与tomcat相关配置】

    Java后端 学习路线 笔记汇总表[黑马程序员] Servlet和HTTP请求协议-学习笔记01[Servlet_快速入门-生命周期方法.Servlet_3.0注解配置.IDEA与tomcat相关配置 ...

  6. JDBC学习笔记01【JDBC快速入门、JDBC各个类详解、JDBC之CRUD练习】

    黑马程序员-JDBC文档(腾讯微云)JDBC笔记.pdf:https://share.weiyun.com/Kxy7LmRm JDBC学习笔记01[JDBC快速入门.JDBC各个类详解.JDBC之CR ...

  7. 180天Linux小白到大神-Linux快速入门

    01.Linux快速入门 01.Linux快速入门 1.计算机组成原理 1.1 什么是计算机 1.2 为什么要有计算机 1.3 计算机五大组成部分 1.3.1 CPU 1.3.2 内存/硬盘 1.3. ...

  8. Medusa(美杜莎)和Hydra(九头蛇)快速入门手册:01

    今天主要是初步介绍一些Hydra和Medusa的分析和内容,旨在方便快速入门,这是第一部分Medusa,后面附带一些字典,之所以是写一起,我是觉得这两个都是不错的工具,不应该分开的,在这种思想下就汇总 ...

  9. Filter和Listener-学习笔记01【Filter 快速入门】

    Java后端 学习路线 笔记汇总表[黑马程序员] Filter和Listener-学习笔记01[Filter快速入门] Filter和Listener-学习笔记02[Filter细节] Filter和 ...

  10. Cookie和Session-学习笔记01【Cookie_快速入门、Cookie_细节】

    Java后端 学习路线 笔记汇总表[黑马程序员] Cookie和Session-学习笔记01[Cookie_快速入门.Cookie_细节] Cookie和Session-学习笔记02[Cookie案例 ...

最新文章

  1. PySpider HTTP 599: SSL certificate problem错误的解决方法
  2. 人脸识别种族偏见:黑黄错误率比白人高100倍 | 美官方机构横评189种算法
  3. c语言调用hzk16,C语言使用HZK16显示每个像素的代码
  4. Perl 中的正则表达式
  5. 在 VirtualBox 中 CentOS 网络设置
  6. 我的第一个python web开发框架(11)——工具函数包说明(二)
  7. oracle 日期 加一秒,Leap Second (闰秒) 在ORACLE环境的影响
  8. 亚马逊CEO贝索斯将飞往太空;字节跳动获得“字节汽车”商标;谷歌被法国反垄断机构罚款 2.2 亿欧元|极客头条...
  9. visio绘图:通过excel在visio中插入表格
  10. matlab:使用全局变量
  11. 登录和访问EI(Engineering Village)数据库查找文献
  12. Markdown学习笔记
  13. 电路实验一阶电路误差分析_动态电路分析
  14. 淘宝导航css相关说明
  15. 【IoT】战略:BEM 战略解码 - 好的战略需要好的执行
  16. 全球四大卫星导航系统
  17. java:定义一个Shape类,派生出Circle类和Rectangle类,手写模拟GeoArrayList,实现升序(升序以面积大小判断)存入Circle类和Rectangle类
  18. 记事本改字体的代码java_求java记事本代码(带字体设置功能)?
  19. 升降压电路的工作原理
  20. 100+问说清放大器噪声那些事儿,超实用技巧

热门文章

  1. byte为什么是-128-127
  2. 伤寒杂病论.辨阳明病脉证并治
  3. A. Bear and Big Brother
  4. How to caching Global data in on-chip (level 1) cache in Morden GPU
  5. 编程之余—80后夫妻公约
  6. 纽约大学计算机与科学,纽约大学计算机科学专业排名第30(2020年USNEWS美国排名)...
  7. springboot banner.txt文件
  8. 我的世界java英文版,大量教程
  9. ESP32-S2 st7789 SPI TFT彩屏240X320
  10. 湖南高校教师资格证笔试内容