所用书籍:《spring实战(第四版)》
《spring实战(第五版)》
未更新完
引言
注入,举个例子通俗地说就是把这个对象(bean)与这个类相关联,被这个类使用。而IOC容器这些,讲的就是一个动态注入,平时编译器写的都是静态的。
这里先要提到Bean中的POJO,是一个普通对象, 可以方便地融入Spring和非Spring应用之中。
自然也可以由依赖注入,使得这个POJO能被外部管理,注入依赖关系。
尽管POJO形式看起来很简单,但 POJO 一样可以具有魔力。Spring 赋予 POJO 魔力的方式之一就是通过 依赖注入 来【装配】它们。
而Ioc容器就是依赖注入的载体,一般可以用XML、Java的方式描述配置装配这两个应用组件。
此处需要说明的是,集合类容器和Ioc容器有很大不同。集合类容器是存储对象的,是一种数据结构,IoC容器是一种基于Java反射机制(像镜子一样把运行时的一个对象反射出来,即动态访问和操作,不用静态的时候获取)和XML配置文件的容器,负责管理对象与程序的依赖关系的。
同时,面向切片编程指的是对面向对象编程的一种补充和延展。接口是对对象的方法和行为进行抽象,切面是对通用方法进行抽象;切面重点在于【管理】与业务逻辑无关的“切入点”上面,比如日志的记录等,意在从冗杂的通用方法抽离出来。
注意,这里的切面是横切面,横切面是指与人体或器官的长轴垂直的切面。
举个例子就是在电商网站需要提交订单的时候要进行一系列的验证与安全操作,而这部分的代码在传统领域中必须在每一个相关的业务逻辑中都写上,目前的理解是传统方法是把 统一的验证逻辑,一个个分配到需要被分配的地方去,这样就冗余。而切片管理是在外面把验证逻辑与这些函数关联,在这架构下自动联系上,更加的智能,就好像在业务逻辑外面写了个when什么什么的时候,使用切面里的安全验证代码。
再一个要谈的是Spring的非侵入式编程。这里可以认为是,由于那些“切入点”是切面,但他们与主要逻辑无关,因此可以贯彻、贯穿整个系统,是系统的一个切面,因此他们通过代理对象的方法,不破坏代码、不侵入代码、不修改代码来实现AOP功能。
切面的特点:
“它们通常具有横向和纵向两个特点,即横向穿插在应用程序中的多个模块中,同时纵向贯穿于整个应用程序的生命周期。”
完整的Spring的库中的JAR文件分为六个功能的模块:
还要提一下Spring Portfolio,他是spring团队推出的产品、框架的集合。其包含:
- Spring Framework
- Spring Boot
- Spring Data
- Spring Security
- Spring Cloud
……
最后一个要谈的是spring的特点:
- 轻量化
- 易测试
- 可多种数据访问
- 模块化
- 面向切面编程
- 容器化
第一部分 spring核心部分
简单地说,DI 能够让相互协作的软件组件保持松散耦合,也就是简化以及较容易维护依赖关系、管理依赖关系,而面向切面编程(aspect-oriented programming,AOP)允许你把遍布应用各处的功能分离出来形成可重用的组件。
依赖注入
spring其他的功能模块都是在spring 的核心特性:依赖注入(DI)、面向切面编程(AOP)之上建立的。因此这两部分是基础学习部分。
再一个,Spring 的目标是致力于全方位的简化 Java 开发。
依赖注入的第一个例子是构造器注入,也就是构造器参数传递。
先来看代码:
在这里插入代码片
package sia.knights;
public class DamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
this.quest = new RescueDamselQuest();
}
public void embarkOnQuest() {
quest.embark();
}
}
这块代码是实现了勇者接口的一个专门营救公主的骑士类,在这类的构造器中新实例化了一个营救少女任务,如此一来这个勇者和这个任务紧紧绑定耦合在一起,他只能营救公主,而不能做别的任务,同时测试也会很困难。
如果利用依赖注入中的构造器参数注入,则变成如下:
package sia.knights;
public class BraveKnight implements Knight {
private Quest quest;
public BraveKnight(Quest quest) {
this.quest = quest;
}
public void embarkOnQuest() {
quest.embark();
}
}
在这个更不与任务耦合的勇士类中在实例化的时候把需要让他执行的任务传入即可,也方便进行测试。
而以下是猎杀龙的任务
package sia.knights;
import java.io.PrintStream;
public class SlayDragonQuest implements Quest {
private PrintStream stream;
public SlayDragonQuest(PrintStream stream) {
this.stream = stream;
}
public void embark() {
stream.println("Embarking on quest to slay the dragon!");
}
}
通过依赖注入就能将这个quest和knight装配在一起,采用XML来配置比较常见,或者也可以使用Java来装配。
装配后就能将这个写好的具体的quest注入到knight了
应用切面
这里举一个吟游诗人的例子,他可以在骑士完成任务前后都吟唱。吟唱这个动作可以作为应用切面的一个非核心的关注点。
而此时embark(执行任务)就是一个切入点,吟唱在embark前后都有进行,以下是配置文件的一部分:
<aop:config>
<aop:aspect ref="minstrel">
<aop:pointcut id="embark"
expression="execution(* *.embarkOnQuest(..))"/>
<aop:before pointcut-ref="embark"
method="singBeforeQuest"/>
<aop:after pointcut-ref="embark"
method="singAfterQuest"/>
</aop:aspect>
</aop:config>
在这种情况下,我们用少量的xml就配置好了切面。
以上都是一些简化过程。
Spring 工厂
bean工厂
是最简单的容器,提供基本的DI支持。一般对应用来说过于低级,因此不学习讨论。
应用上下文
举例常用的:
- AnnotationConfigApplicationContext:从一个或多个基于 Java 的配置类中加载 Spring 应用上下文
- AnnotationConfigWebApplicationContext:从一个或多个基于 Java 的配置类中加载 Spring Web 应用上下文
- ClassPathXmlApplicationContext:从所有类路径下的一个或多个 XML 配置文件中加载上下文定义,把应用上下文的定义文件作为类资源
- FileSystemXmlapplicationcontext:从指定的文件系统下的一个或多个 XML 配置文件中加载上下文定义(用文件系统路径)
- XmlWebApplicationContext:从 Web 应用下的一个或多个 XML 配置文件中加载上下文定义
bean的生命周期
基于xml管理bean
获取bean的方式
注意此时从书籍的学习转换到了尚硅谷的视频学习。
- 用id获取
- 用类型获取
- 用id和类型获取
需要注意的是,当用第三个【类型来获取】的时候,如果获取时使用的类型有且只能有一个,否则会产生报错。
类似的,用接口类型来获取bean的时候:这个接口有两个实现方法,配置了这俩实现方法后,此时获取bean也会报同样的错。(因为接口实现类返回的bean不唯一,如果只有一个接口实现,则不报错)
依赖注入
setter方法注入、构造器注入
注入的时候有些特殊值需要注意:如null、xml实体、cdata
对象类型赋值
-
外部引入
-
内部引入
-
级联赋值
注意级联赋值的时候,对象属性的类中要写对这个对象属性的getter方法,否则会报错,需要获得这个属性,才能进一步地设置。
p命名空间简化操作
面向切面
代理分为静态代理和动态代理,面向切面是基于动态代理实现的。
方式又分为有接口和无接口的。