Spring是什么
- 轻量级:Spring 是非侵入性的 - 基于 Spring 开发的应用中的对象可以不依赖于 Spring 的 API
- 依赖注入(DI — dependency injection、IOC)
- 面向切面编程(AOP — aspect oriented programming)
- 容器: Spring 是一个容器, 因为它包含并且管理应用对象的生命周期
- 框架: Spring 实现了使用简单的组件配置组合成一个复杂的应用. 在 Spring 中可以使用 XML 和 Java 注解组合这些对象
- 一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库 (实际上 Spring 自身也提供了展现层的 SpringMVC 和 持久层的 Spring JDBC)
IOC & DI 概述
推荐一个知乎帖子,从概念上形象的说明了IOC的思想:https://www.zhihu.com/question/23277575
IOC(Inversion of Control):其思想是反转资源获取的方向. 传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应, 容器适时的返回资源. 而应用了 IOC 之后, 则是容器主动地将资源推送给它所管理的组件, 组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式
**DI(Dependency Injection) **:IOC 的另一种表述方式:即组件以一些预先定义好的方式(例如: setter 方法)接受来自如容器的资源注入. 相对于 IOC 而言,这种表述更直接
需求:从容器中获取 B 对象,并使 B 对象的 a 属性被赋值为容器中 A 对象的引用
传统方式:
class A{}
class B{
private A a;
public void setA(A a){
this.a = a;
}
}
IOC:
B b = getB();
注:本篇博客中使用的类,出于简洁,大部分不提供其实现,都是最基本的bean
Spring容器
在 Spring IOC 容器读取 Bean 配置创建 Bean 实例之前, 必须对它进行实例化. 只有在容器实例化后, 才可以从 IOC 容器里获取 Bean 实例并使用.
Spring 提供了两种类型的 IOC 容器实现:
- BeanFactory: IOC 容器的基本实现
- ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口.
BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory.无论使用何种方式, 配置文件时相同的.
ApplicationContext 的主要实现类:
- ClassPathXmlApplicationContext:从 类路径下加载配置文件
- FileSystemXmlApplicationContext: 从文件系统中加载配置文件
ApplicationContext 在初始化上下文时就实例化所有单例的 Bean。通过ApplicationContext中的getBean()方法来从IOC容器中获取Bean。
依赖注入的方式 (Bean 的配置方式)
基于 XML 文件的方式
通过全类名(反射)
属性注入
- 属性注入即通过 setter 方法(即对应的属性在类中要有对应的set方法)注入Bean 的属性值或依赖的对象
- 属性注入使用
<property>
元素, 使用 name 属性指定 Bean 的属性名称,value 属性或<value>
子节点指定属性值 - 属性注入是实际应用中最常用的注入方式
<bean id="helloWorld" class="com.atguigu.spring.helloworld.HelloWorld">
<!-- 为属性赋值,对应的属性需要有对应的set方法赋值才会成功,例如此处在HelloWorld类中需要有setName()方法 -->
<property name="user" value="Jerry"></property>
</bean>
构造器注入
**分为按索引匹配入参和按类型匹配入参两种:** ```<!-- 若一个 bean 有多个构造器, 如何通过构造器来为 bean 的属性赋值 -->
<!-- 可以根据 index 和 value 进行更加精确的定位. 可以通过index与type混合使用,不标明index则默认依次的顺序 -->
<bean id="car" class="com.atguigu.spring.helloworld.Car">
<!-- 构造器的参数是String,String,int -->
<!-- 使用构造器注入属性可以指定参数的位置和参数的类型 ,以区分重载的构造器-->
<constructor-arg value="KUGA" index="1"></constructor-arg>
<constructor-arg value="ChangAnFord" index="0"></constructor-arg>
<constructor-arg value="250000" type="float"></constructor-arg>
</bean>
<bean id="car2" class="com.atguigu.spring.helloworld.Car">
<constructor-arg value="ChangAnMazda" type="java.lang.String"></constructor-arg>
<!-- 若字面值中包含特殊字符, 则可以使用 CDATA 来进行赋值.例如如下包含“<>”的情况 (了解) -->
<constructor-arg>
<value><![CDATA[<ATARZA>]]></value>
</constructor-arg>
<!-- 使用如下value子结点的方式注入属性也是可以的 -->
<constructor-arg type="int">
<value>250</value>
</constructor-arg>
</bean>
引用其它Bean
组成应用程序的 Bean 经常需要相互协作以完成应用程序的功能. 要使 Bean 能够相互访问, 就必须在 Bean 配置文件中指定对 Bean 的引用。在 Bean 的配置文件中, 可以通过 <ref>
元素或 ref 属性为 Bean 的属性或构造器参数指定对 Bean 的引用,也可以在属性或构造器里包含 Bean 的声明, 这样的 Bean 称为内部 Bean。
内部Bean:
<!-- 声明使用内部 bean -->
<bean id="service2" class="com.atguigu.spring.ref.Service">
<property name="da