Spring是最受欢迎的企业级Java应用程序开发架构,数以百万的来自世界各地开发人员使用spring框架来创建性能好、易于测试、可重用的代码。
Spring框架是一个开源的Java平台,它最初是由Rod Johnson编写的,并且于2003年6月首次在Apache2.0许可下发布
Spring是轻量级的框架,其基础版本只有2MB左右大小
Spring框架的核心特性是可以用于开发任何Java应用程序,但是在JavaEE平台上构建web应用程序是需要拓展的。Spring框架的目标是使J2EE开发变得更容易使用,通过启用基于POJO编程模型来促进良好的编程实践。
Spring基础框架,可以视为Spring基础设备,基本上任何其他Spring项目都是以Spring Framework为基础的。
功能模块 | 功能介绍 |
---|---|
Core Container | 核心容器,在Spring环境下使用任何功能都必须基于IOC容器 |
AOP & Aspects | 面向切面编程 |
Testing | 提供了对junit或TestNG测试框架的整合 |
Data Access/Integration | 提供了对数据访问/集成的功能 |
Springmvc | 提供了面向web应用程序的集成功能 |
IOC:Inversion of Control 翻译过来是反转控制
在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式,增加了学习成本,同时降低了开发效率。
反转控制的思想完全颠覆了应用程序组件获取资源的传统方式,反转了资源的获取方向–改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供资源的方式即可,极大降低了学习成本,提高了开发效率。这种行为也称为查找的被动形式
DI是IOC的另一种表达方式:即组件以一些预先定义好的方式(例如:setter方法)接受来自于容器的资源注入。相当于IOC而言,这种表述更直接
结论:IOC就是一种反转控制的思想,而DI是对IOC的一种具体实现
Spring的IOC容器就是IOC思想的一个落地的产品实现。IOC容器中管理的组件也叫bean。在创建bean之前,首先需要创建IOC容器。Spring提供了IOC容器的两种实现方式:
这是IOC容器的基本实现,是Spring内部使用的接口。面向Spring本身,不提供给开发人员使用。
BeanFactory的子接口,提供了更多高级特性。面向Spring的使用者,几乎所有场合都使用ApplicationContext而不是底层的BeanFactory。
类型名 | 简介 |
---|---|
ClassPathXmlApplicationContext | 通过读取类路径下的xml格式的配置文件创建IOC容器对象 |
FileSystemXmlApplicationContext | 通过文件系统路径读取XML格式的配置文件创建IOC容器对象 |
ConfigurableApplicationContext | ApplicationContext的子接口,包含一些拓展refresh()和close(),让ApplicationContext具有启动、关闭和刷新上下文的能力 |
WebApplicationContext | 专门为Web应用准备,基于web环境创建IOC容器对象,并将对象引入存入ServletContext域中 |
ctrl+h查看当前类或接口的一个继承实现关系
org.sunyur.springframework
spring-context
5.3.1
junit
junit
4.12
test
先创建一个类 定义一个sayHello方法
再创建一个spring配置文件 选中resources - new - XML Configuration File - Spring Config->applicationContext.xml
<bean id="helloworld" class="全类名路径">bean>
对象交给IOC容器管理,验证下先获取IOC,再获取IOC中对象
测试
//获取IOC容器
ApplicationContext ioc = new ClassPathXmlApplicationContext("配置文件路径")
//resources与Java都会被加载到同一路径下,就是类路径下
//获取IOC容器中bean对象 根据bean的id获取bean对象
HelloWorld helloworld=(HelloWorld)ioc.getBean("bean的唯一标识id")//因为我们是通过id获取的,所以并不清楚他是什么类型,可以通过强转改变
helloworld.sayHello()
大部分通过反射创建实例化对象都是使用无参构造方法
删除无参构造运行会报错得到NoSuchMethodException
根据bean的id获取 getBean(String name) 返回object
根据bean的类型获取 getBean(Class requiredType) 直接传入bean的类型 返回类型 较多使用 一个类型的bean只需要配置一次即可
注意:根据类型获取bean时,要求IOC容器中有且只有一个类型匹配的bean
根据bean的类型和id获取getBean(String name,Class requiredType)
第二种情况中applicationContext.xml内有两个或多个bean id的bean,但是类型相同
当使用 getBean(Class requiredType)调用的时候就会出现NoUniqueBeanDefinitionException
第二种情况中applicationContext.xml内一个bean都没有
当使用 getBean(Class requiredType)调用的时候就会出现NoSuchBeanDefinitionException
在applicationContext.xml中bean的参数scope设置单例或者多例
如果组件类实现了接口,根据接口类型可以获取bean吗?
可以,前提是bean是唯一
如果一个接口有多个实现类,这些实现类都配置了bean,根据接口类型可以获取bean吗?
不行,因为bean不唯一
根据类型来获取bean时,在满足唯一性的前提下,其实只是看【对象instanceof指定的类型】的返回结果,只要返回的是true就可以认定为和类型匹配,能够获取到
即通过bean的类型,bean所继承的类的类型、bean所实现的接口都可以获取bean
public class Student{
private Integer id;
private String name;
private Integer age;
private String sex;
//加上 get/set toString
}
可以看出Student这个类依赖于属性 id name age sex 那么就可以在IOC容器中为它所依赖的属性进行赋值 为当前属性进行赋值就称为依赖注入
注入有set注入与构造器注入
<bean id="唯一标识" class="类的全类名路径">
<property name="属性名" value="给予的值">property> //鼠标悬停可以发现name的位置出现了set方法。。。
bean>
<bean id="唯一标识id" class="类的全类名路径">
<constructor-arg value="">constructor-arg>
bean>
什么是字面量?
int a = 10;
声明一个变量a,初始化为10,此时a就不代表字母a了,而是作为一个变量的名字。当我们引用a的时候,我们实际上拿到的值是10
而如果a是带引号的:‘a’,那么它现在不是一个变量,它就是代表a这个字母本身,这就是字面量。所以字面量没有引申含义,就是我们看到的这个数据本身
<property name="name" value="张三">
<property name="name">
<null />
property>
<property name="name" value="null">property> 为name所赋的值是字符串null
<:< >:>大小符号
<property name="expression" value="a < b"/>
<property name="expression">
<value>![CDATA[avalue>
property>
private Integer cid;
private String cname;
设置有参/无参构造方法 get/set方法 toString方法 对一对应对象 对多对应集合
表示学生所对应的班级,在学生类中加入班级类型的属性 Clazz clazz(不能使用value,value是给字面量初始赋值的)
给类类型赋值的话有三种方式
<bean id="唯一标识符id class="类的全类名路径">
<property name="属性名" value="字面量赋值">property>//property要与构造方法匹配 进行set赋值
<property name="clazz" ref="引用clazz的bean id">property>//ref引用IOC容器中的某个bean的id
bean>
<bean id="唯一标识id" class="类的全类路径">//Clazz
<property name="" value="">property>//为clazz中属性赋值set设置值
bean>
<bean id="唯一标识符id class="类的全类名路径">
<property name="属性名" value="字面量赋值">property>//property要与构造方法匹配 进行set赋值
<property name="clazz" ref="引用clazz的bean id">property>//ref引用IOC容器中的某个bean的id
<property name="clazz.属性名" value="xxx">property>//要对应类中的属性数量 这里级联相当于修改了下面赋值的值
bean>
<bean id="唯一标识id" class="类的全类路径">//Clazz
<property name="" value="">property>//为clazz中属性赋值set设置值
bean>
<bean id="唯一标识符id class="类的全类名路径">
<property name="属性名" value="字面量赋值">property>//property要与构造方法匹配 进行set赋值
<property name="clazz">
<bean id="唯一标识id" class="类的全类名路径">
<property name="直接填写clazz的属性名不用带clazz" value>property>
bean>
property>
bean>
测试尝试从内部bean能不能通过ioc容器获取 显然不行报 NoSuchBeanDefinitionException
No bean named ‘clazz’ available 没有一个叫clazz的bean可用
内部bean,只能在当前bean的内部使用,不能直接通过IOC容器获取
在Student类中加入String[] hobby,在生成get/set 构造 toString方法
<property name="唯一标识">
<array>
<value>赋值value>
array>
property>
在班级Clazz类中添加 List student 多对一对象 一对多集合
<bean id="唯一标识id" class="类的全类路径">//clazz类
<property name="" value="">property>//为clazz类中属性赋值
<property name="students">
<list>
<ref bean="引用ioc容器中其他bean">ref>
list>
property>
bean>
<util:list id="唯一标识"><ref bean="ioc中其他bean">ref>util:list> //引入util list标签 直接用就可以在applicationContext.xml中使用
新建一个Teacher类 get/set toString 有参/无参构造
在学生类Student类中添加Map
//先找到一个学生bean
<property name="属性名">
<map>
<entry key="10086" value-ref="唯一标识1(其他bean id)">entry>
<entry key="10010" value-ref="唯一标识2(其他bean id)">entry> key,value要根据map定义的类型决定
map>
property>
<bean id="唯一标识1" class="类的全类名路径">
<property name="属性名" value="赋值">property> //根据类的属性数量 也就是构造方法中参数数量