框架
Spring IoC⭐
IoC
IoC 控制反转,把对象创建、依赖反转给容器实现,需要创建一个容器和一种描述让容器知道对象间的依赖关系,Spring 通过 IoC 容器管理对象及其依赖关系。IoC 的主要实现方式是 DI,对象不是从容器中查找依赖的类,而是容器实例化对象时主动为它注入依赖的类。
基于 XML 的 IoC 初始化
当创建 ClassPathXmlApplicationContext 时,调用父类 AbstractApplicationContext 的 refresh
方法启动整个 IoC 容器对 Bean 定义的载入过程,在创建 IoC 容器前如果已有容器存在,需要销毁,保证使用的是新创建的容器。
容器创建后通过 loadBeanDefinitions
方法加载 Bean 配置资源,首先解析配置文件路径,读取配置文件内容,然后通过 XML 解析器将配置信息转换成文档对象,之后按照 Bean 的定义规则解析文档对象。
IoC 容器中注册的 Bean 信息存放在一个 HashMap 中,key 是字符串,值是 BeanDefinition。当配置信息中的 Bean 被解析且被注册到 IoC 容器后,初始化就算完成了。
DI
实现
-
构造方法注入
IoC 容器会检查对象的构造方法,取得它的依赖对象列表,当对象实例化完成时依赖的属性也会成功注入,可以直接使用。缺点是当依赖对象较多时,可能需要多个构造方法。
-
setter 方法注入
只需要为依赖对象的属性添加 setter 方法,在描述性上要比构造方法注入强,缺点是无法在对象构造完成后就进入就绪状态。IoC 容器会先实例化 Bean 对象,然后通过反射调用 setter 方法注入属性。
-
注解注入
@Autowired
:自动按类型注入,如果有多个匹配则按照指定 Bean 的 id 查找,需要搭配@Qualifier
。@Resource
:按照 Bean 的 id 注入,如果找不到则会按类型注入。@Value
:用于注入基本数据类型和 String。
Bean
生命周期
在 IoC 容器的初始化时会对 Bean 定义完成资源定位,加载读取配置并解析,最后将解析的 Bean 信息放在一个 HashMap 集合中。当 IoC 容器初始化后,会创建 Bean 实例并完成依赖注入,注入对象依赖的各种属性值,在初始化时可以指定自定义的初始化方法。经过一系列初始化操作后 Bean 达到可用状态,当使用完成后会调用 destroy 方法进行销毁,此时也可以指定自定义的销毁方法,最终 Bean 被销毁且从容器中移除。
通过配置 bean 标签或注解中的 init-Method 和 destory-Method 属性指定自定义初始化和销毁方法。
作用域
通过 scope 属性指定作用域。
范围 | 作用域 | 备注 |
---|---|---|
所有 Spring 应用 | singleton | 默认作用域,每个容器中只有一个唯一的 Bean 实例。 |
prototype | 每次 Bean 请求都会创建一个新的实例。 | |
Spring Web 应用 | request | 为每个请求创建一个新的实例。 |
session | 为每个会话创建一个新的实例。 | |
global session | 为全局 session 创建一个新的实例。 |
创建
-
XML
默认无参构造方法,只需指明 bean 标签中的 id 和 class 属性,如果没有无参构造方法会报错。
静态工厂方法,通过 bean 标签的 class 属性指明工厂,factory-method 属性指明方法。
实例工厂方法,通过 bean 标签的 factory-bean 属性指明工厂,factory-method 属性指明方法。
-
注解
@Component
把当前类对象存入 Spring 容器,相当于在 xml 中配置一个 bean 标签。value 属性指定 bean 的 id,默认使用当前类首字母小写的类名。@Controller
,@Service
,@Repository
都是@Component
的衍生注解,作用及属性都一模一样,只是提供了更明确的语义,@Controller
用于表现层,@Service
用于业务层,@Repository
用于持久层。如果想注入第三方类又没有源码,就没法使用
@Component
,需要用@Bean
。被@Bean
注解的方法返回值是一个对象,这个对象由 Spring 的 IoC 容器管理,name 属性用于给对象指定一个名称。
BeanFactory、FactoryBean 和 ApplicationContext 的区别
BeanFactory 是一个 Bean 工厂,使用简单工厂模式,是 Spring IoC 容器顶级接口,作用是管理 Bean,包括实例化、定位、配置对象及维护对象间的依赖。BeanFactory 属于延迟加载,适合多例模式。
FactoryBean 是一个工厂 Bean,使用工厂方法模式,作用是生产其他 Bean 实例,可以通过实现该接口来自定义实例 Bean 的逻辑。如果一个 Bean 实现了这个接口,那么它就是创建对象的工厂 Bean,而不是 Bean 实例本身。
ApplicationConext 是 BeanFactory 的子接口,扩展了 BeanFactory 的功能,提供了支持国际化文本消息,统一的资源文件读取方式等功能。Bean 的依赖注入在容器初始化时就已经完成,属于立即加载,适合单例模式。
注解配置文件
@Configuration
指定当前类是一个 Spring 配置类,创建容器时会从该类上加载注解,value
属性指定配置类的字节码。
@ComponentScan
开启组件扫描,basePackages
属性指定要扫描的包。
@PropertySource
用于加载 properties
文件中的配置。
@Import
导入其他配置类,有 @Import
的是父配置类,引入的是子配置类,value 属性指定其他配置类的字节码。
Spring AOP ⭐
AOP
AOP 面向切面编程,将代码中重复的部分抽取出来,使用动态代理技术,在不修改源码的基础上对方法进行增强。
如果目标对象实现了接口,默认采用 JDK 动态代理,也可以强制使用 CGLib;如果目标对象没有实现接口,采用 CGLib 的方式。
常用场景包括权限认证、自动缓存、错误处理、日志、调试和事务等。
相关注解
@Aspect
:声明被注解的类是一个切面 Bean。
@Before
:前置通知,指在某个连接点之前执行的通知。
@After
:后置通知,指某个连接点退出时执行的通知(不论正常返回还是异常退出)。
@AfterReturning
:返回后通知,指某连接点正常完成之后执行的通知,返回值使用 returning 属性接收。
@AfterThrowing
:异常通知,指方法异常退出时执行的通知,和 @AfterReturning
只会有一个执行,异常使用 throwing 属性接收。
相关术语
Aspect
:切面,一个关注点的模块化,这个关注点可能会横切多个对象。
Joinpoint
:连接点,程序执行过程中的某一行为,即业务层中的所有方法。
Advice
:通知,指切面对于某个连接点所产生的动作,包括前置通知、后置通知、返回后通知、异常通知和环绕通知。
Pointcut
:切入点,指被拦截的连接点,切入点一定是连接点,但连接点不一定是切入点。
Proxy
:代理,Spring AOP 中有 JDK 动态代理和 CGLib 代理,目标对象实现了接口时采用 JDK 动态代理,反之采用 CGLib 代理。
Target
:代理的目标对象,指一个或多个切面所通知的对象。
Weaving
:织入,指把增强应用到目标对象来创建代理对象的过程。
Spring MVC ⭐
处理流程
Web 容器启动时初始化 IoC 容器,加载 Bean 的定义信息并初始化所有单例 Bean,遍历容器中的 Bean,获取每个 Controller 中的所有方法访问的 URL,将 URL 和对应的 Controller 保存到一个 Map 集合中。
所有的请求会转发给 DispatcherServlet 处理,DispatcherServlet 会请求 HandlerMapping 找出容器中被 @Controler
修饰的 Bean 以及被 @RequestMapping
修饰的方法和类,生成 Handler 和 HandlerInterceptor 并以一个 HandlerExcutionChain 链的形式返回。
DispatcherServlet 使用 Handler 找到对应的 HandlerApapter,通过 HandlerApapter 调用 Handler 的方法,将请求参数绑定到方法的形参上,执行方法处理请求并得到逻辑视图 ModelAndView。
使用 ViewResolver 解析 ModelAndView 得到物理视图 View,进行视图渲染,将数据填充到视图中并返回给客户端。
组件
DispatcherServlet
:前端控制器,整个流程控制的核心,负责接收请求并转发给对应的处理组件。
Handler
:处理器,完成具体业务逻辑。
HandlerMapping
:处理器映射器,完成 URL 到 Controller 映射。
HandlerInterceptor
:处理器拦截器,如果需要完成拦截处理可以实现该接口。
HandlerExecutionChain
:处理器执行链,包括 Handler 和 HandlerInterceptor。
HandlerAdapter
:处理器适配器,DispatcherServlet 通过 HandlerAdapter 来执行不同的 Handler。
ModelAndView
:逻辑视图,装载模型数据信息。
ViewResolver
:视图解析器,将逻辑视图解析为物理视图。
相关注解
@RequtestMapping
:将 URL 请求和方法映射起来,在类和方法定义上都可以添加。value
属性指定 URL 请求的地址。method
属性限制请求类型,如果没有使用指定方法请求 URL,会报 405 错误。params
属性限制必须提供的参数。
@RequestParam
:如果 Controller 方法的形参和 URL 参数名不一致可以使用该注解绑定。value
属性表示 HTTP 请求中的参数名,required
属性设置参数是否必要,默认false。defaultValue
属性指定没有给参数赋值时的默认值。
@PathVariable
:Spring MVC 支持 RESTful 风格 URL,通过 @PathVariable
完成参数绑定。
Spring Data JPA
ORM
Object-Relational Mapping ,表示对象关系映射,映射的不只是对象的值还有对象之间的关系,通过 ORM 就可以把对象映射到关系型数据库中。操作实体类就相当于操作数据库表,可以不再重点关注 SQL 语句。
JPA 的使用
只需要持久层接口继承 JpaRepository 即可,泛型参数列表中第一个参数是实体类类型,第二个参数是主键类型。
运行时通过 JdkDynamicAopProxy
的 invoke
方法创建了一个动态代理对象 SimpleJpaRepository
,SimpleJpaRepository
中封装了 JPA 的操作,通过 hibernate 完成数据库操作。
实体类相关注解
@Entity
:表明当前类是一个实体类。
@Table
:关联实体类和数据库表。
@Column
:关联实体类属性和数据库表中字段。
@Id
:声明当前属性为数据库表主键对应的属性。
@GeneratedValue
: 配置主键生成策略。
@OneToMany
:配置一对多关系,mappedBy 属性值为主表实体类在从表实体类中对应的属性名。
@ManyToOne
:配置多对一关系,targetEntity 属性值为主表对应实体类的字节码。
@JoinColumn
:配置外键关系,name 属性值为外键名称,referencedColumnName 属性值为主表主键名称。
对象导航查询
通过 get 方法查询一个对象的同时,通过此对象可以查询它的关联对象。
对象导航查询一到多默认使用延迟加载, 关联对象是多个对象,使用立即加载可能浪费资源;对象导航查询多到一默认使用立即加载。
实体类注解的 fetch 属性表示加载方式,LAZY 是延迟加载,EAGER 是立即加载。
Mybatis⭐
XML 标签
select
、insert
、update
、delete
标签分别对应查询、添加、更新、删除操作。
parameterType
属性表示参数的数据类型,包括基本数据类型和对应的包装类型、String 和 Java Bean 类型,当有多个参数时可以使用 #{argn}
的形式表示第 n 个参数。除了基本数据类型都要以全限定类名的形式指定参数类型。
resultType
表示返回的结果类型,包括基本数据类型和对应的包装类型、String 和 Java Bean 类型。还可以使用把返回结果封装为复杂类型的 resultMap
。
一级缓存
一级缓存是 SqlSession 级别,默认开启。
SqlSession 对象中有一个 HashMap 缓存数据,不同 SqlSession 间缓存数据互不影响。同一个 SqlSession 中执行两次相同的 SQL 语句时,第一次执行完毕会将结果保存在缓存中,第二次查询直接从缓存中获取。
如果 SqlSession 执行了 DML 操作(insert、update、delete),Mybatis 必须将缓存清空保证数据有效性。
二级缓存
二级缓存是Mapper 级别,默认关闭。
相比于一级缓存,缓存范围更大,多个 SqlSession 可以共用二级缓存,作用域是 Mapper 的同一个 namespace,不同 SqlSession 两次执行相同的 namespace 下的 SQL 语句,参数也相等,则第一次执行成功后会将数据保存在二级缓存中。
需要在全局配置文件中配置
,并在对应的映射文件中配置
标签。
#{}
和 ${}
的区别
使用 ${}
相当于使用字符串拼接,存在 SQL 注入的风险。
使用 #{}
相当于使用占位符,可以防止 SQL 注入,不支持使用占位符的地方就只能使用 ${}
,典型情况就是动态参数。
SpringBoot⭐
优点
简化开发:它的作用就是快速搭建 Spring 框架。
简化配置:比如要创建一个 web 项目,在使用 Spring 的时候,需要在 pom 文件中添加多个依赖,而在 SpringBoot 中只需要添加一个 starter-web 依赖即可。
简化部署:使用 Spring 时需要部署 tomcat,然后把项目打成 war 包。而 SpringBoot 内嵌了 tomcat,只需要将项目打成 jar 包即可。
注解
@SpringBootApplication
:自动给程序进行必要配置,这个配置等同于:@Configuration
,@EnableAutoConfiguration
和 @ComponentScan
三个配置。
@EnableAutoConfiguration
:允许 SpringBoot 自动配置注解,开启后 SpringBoot 就能根据当前类路径下的包或者类来配置 Bean。
@SpringBootConfiguration
:相当于 @Configuration
,只是语义不同。
SpringCloud⭐
微服务的优点
各个服务的开发、测试、部署都相互独立,用户服务可以拆分为独立服务,如果用户量很大,可以很容易对其实现负载。
当新需求出现时,使用微服务不再需要考虑各方面的问题,例如兼容性、影响度等。
使用微服务拆分项目后,各个服务之间消除了很多限制,只需要保证对外提供的接口正常可用,而不限制语言和框架等选择。
服务治理 Eureka
服务治理由三部分组成:服务提供者、服务消费者、注册中心。
服务注册:在分布式系统架构中,每个微服务在启动时,将自己的信息存储在注册中心。
服务发现:服务消费者从注册中心获取服务提供者的网络信息,通过该信息调用服务。
Spring Cloud 的服务治理使用 Eureka 实现,Eureka 是 Netflix 开源的基于 REST 的服务治理解决方案,Spring Cloud 集成了 Eureka,提供服务注册和服务发现的功能,可以和基于 Spring Boot 搭建的微服务应用轻松完成整合。
服务网关 Zuul
Spring Cloud 集成了 Zuul 组件,实现服务网关。
Zuul 是 Netflix 提供的一个开源的 API 网关服务器,是客户端和网站后端所有请求的中间层,对外开放一个 API,将所有请求导入统一的入口,屏蔽了服务端的具体实现逻辑,可以实现方向代理功能,在网关内部实现动态路由、身份认证、IP过滤、数据监控等。
负载均衡 Ribbon
Ribbon 是 Netflix 发布的均衡负载器,Spring Cloud 集成了 Ribbon,提供用于对 HTTP 请求进行控制的负载均衡客户端。
在注册中心对 Ribbon 进行注册之后,Ribbon 就可以基于某种负载均衡算法(轮循、随机、加权轮询、加权随机等)自动帮助服务消费者调用接口,开发者也可以根据具体需求自定义 Ribbon 负载均衡算法。实际开发中 Spring Clooud Ribbon 需要结合 Spring Cloud Eureka 使用,Eureka 提供所有可以调用的服务提供者列表,Ribbon 基于特定的负载均衡算法从这些服务提供者中选择要调用的实例。
声明式接口调用 Feign
Feign 是 Netflix 提供的,一个声明式、模板化的 Web Service 客户端,简化了开发者编写 Web 客户端的操作,开发者可以通过简单的接口和注解来调用 HTTP API。
相比于 Ribbon + RestTemplate 的方式,Feign 可以大大简化代码开发,支持多种注解,包括 Feign 注解、Spring MVC 注解等。
RestTemplate 是 Spring 框架提供的基于 REST 的服务组件,底层是对 HTTP 请求及响应进行了封装,提供了很多访问 REST 服务的方法,简化代码开发。
服务配置 Config
Spring Cloud Config 通过服务端可以为多个客户端提供配置服务,既可以将配置文件存储在本地,也可以将配置文件存储在远程的 Git 仓库,创建 Config Server,通过它管理所有的配置文件。
服务跟踪 Zipkin
Spring Cloud Zipkin 是一个可以采集并跟踪分布式系统中请求数据的组件,让开发者更直观地监控到请求在各个微服务耗费的时间,Zipkin 包括两部分 Zipkin Server 和 Zipkin Client。
服务熔断 Hystrix
熔断器的作用:在不改变各个微服务调用关系的前提下,针对错误情况进行预先处理。
设计原则:服务隔离、服务降级、熔断机制、提供实时监控和报警功能、提供实时配置修改功能。
Hystrix 数据监控需要结合 Spring Boot Actuator
使用,Actuator 提供了对服务的数据监控、数据统计,可以通过 hystirx-stream
节点获取监控的请求数据,同时提供了可视化监控界面。
参考资料
[1] # SpringMVC常用注解整理