Spring 体系结构,核心理念


 

相关问题

  • 什么是spring?谈谈你对spring的理解
  • spring有什么优缺点
  • spring的体系结构是怎样的?spring有哪些模块?
  • spring中有哪些核心组件?
  • spring有什么特性?
  • spring是怎么实现aop的?spring有几种方式实现aop?spring aop的原理是什么?
  • spring中用到了哪些设计模式?
  • spring中有哪几种配置方式?

 

说明

  • 本文使用的spring源码版本是 5.3.x
  • 源码的一些方法上标注得有 spring的 @Nullable 注解,提醒开发者方法返回值可以为null。为了节省篇幅,我把注释和方法上标注的 @Nullable 都去了。

 

spring概述

spring的设计目标

设计目标 | 设计初衷

  • 解决企业级应用开发的复杂性,即简化Java开发
  • 为开发者提供一个一站式轻量级应用开发平台;

为了降低Java开发的复杂性,Spring采取了以下4种关键策略

  • 基于POJO的轻量级和最小侵入性编程;
  • 通过依赖注入和面向接口实现松耦合;
  • 基于切面和惯例进行声明式编程;
  • 通过切面和模板减少样板式代码。

 

spring的设计理念

BOP,bean oriented programming 面向bean编程

  • bean是spring中的核心概念,是spring应用中的核心java对象;
  • spring本身围绕bean进行设计,使用 BeanDefinition 封装bean的定义,使用 BeanFactory 获取bean的实例;
  • spring容器其实是 spring bean container 是bean的容器,负责bean的实例化、装配、管理;
  • 使用spring进行开发其实是面向bean进行编程,开发的主要任务是编写、配置bean。

 

spring的优缺点

优点|好处

  • 轻量,非侵入式设计,降低代码耦合度
  • 提供了IoC容器,开发者不必关心对象的创建过程、对象间复杂的依赖关系
  • 支持AOP,把业务逻辑和横切逻辑分离开来
  • 是一站式解决方案,提供了测试、web、数据访问、事务管理、异常处理等功能,简化了开发,降低了开发难度
  • 强大的整合能力,可以和很多优秀框架无缝整合
     

缺点

  • spring的设计初衷是轻量级的开发框架,但给人一种大而全的感觉
  • 依赖反射,框架本身大量使用反射,很影响性能,且破坏类封装性。比如创建bean实例时通过反射调用构造方法创建实例,实现@Value、@Autowired时通过反射给字段赋值、调用方法注入依赖,
  • aop使用大量使用动态代理,在运行时动态创建代理,很影响性能

 

spring的体系结构

在这里插入图片描述
spring是轻量级的一站式开发框架,以 IoC、AOP 为核心,集成了Test模块来支持测试,集成了 Data Access 数据访问模块来操作数据源,集成了Web模块来支持web开发。

 

spring的5大版块|功能

  • Test 测试模块:提供对测试的支持
  • Core Container 核心容器模块:实现了spring容器,主要提供IoC/DI功能
  • AOP模块:提供对aop的支持,包括spring aop、aspectj 2种实现方式
  • Data Access/Integration 数据访问/集成模块:提供对数据源操作的支持,包括对jdbc、orm映射框架、xml解析、消息队列、事务管理的支持
  • Web模块:提供对web应用的支持。在目前最新的5.x版本中,Web模块已经废弃了 Portlet 组件,同时增加了用于异步响应式处理的 WebFlux 组件。

 

Core Container 核心容器模块分为4个小模块

  • Beans:提供BeanDefinition、BeanFactory,实现了容器的核心功能 IoC
  • Core:提供Resource,集成了对多种资源的访问、解析能力
  • Context:建立在Beans、Core模块的基础上,实现了高级容器ApplicationContext,用于暴露给开发者使用,以及整合其它框架时对第三方库提供支持
  • SpEL:提供对Spring EL(表达式语言)的支持

 

spring的核心组件

spring的核心是bean,核心组件都是围绕bean进行设计的
 

core模块的Resource

定义对资源的访问,用于加载资源

public interface Resource extends InputStreamSource {

	boolean exists();
	
	default boolean isReadable() {
		return exists();
	}
	
	default boolean isOpen() {
		return false;
	}
	
	default boolean isFile() {
		return false;
	}
	
	URL getURL() throws IOException;
	
	URI getURI() throws IOException;
	
	File getFile() throws IOException;
	
	default ReadableByteChannel readableChannel() throws IOException {
		return Channels.newChannel(getInputStream());
	}
	
	long contentLength() throws IOException;
	
	long lastModified() throws IOException;
	
	Resource createRelative(String relativePath) throws IOException;
	
	String getFilename();
	
	String getDescription();

}

 
Resource接口定义的是通用的资源访问,屏蔽了资源的来源、格式的不同,常见的最终实现类如下

  • UrlResource:实现了对网络资源的访问
  • ClassPathResource:实现了对classpath中的资源访问
  • FileSystemResource:实现了对文件系统中的资源访问
  • InputStreamResource:实现了对输入流中的资源访问
  • ByteArrayResource:实现了对字节数组中的资源访问

 

beans模块的BeanDefinition

用于描述bean的定义、元数据、bean之间的依赖关系。

xml文件或注解定义的bean会被转换为BeanDefinition实例,存储在 BeanFactory 中。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

	//scope常量
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


	//role常量,标识bean在系统中的角色
	int ROLE_APPLICATION = 0;  //开发自定义的bean
	int ROLE_SUPPORT = 1;  //spring中对外提供支持、整合能力,暴露给开发使用的bean
	int ROLE_INFRASTRUCTURE = 2;  //基础设施,spring中的基础bean


	//父BeanDefinition的name
	void setParentName(@Nullable String parentName);
	String getParentName();
	
	
	//BeanClassName,bean对应的java类的类名
	void setBeanClassName(@Nullable String beanClassName);
	String getBeanClassName();
	
	
	//作用域
	void setScope(@Nullable String scope);
	String getScope();
	
	
	//懒加载
	void setLazyInit(boolean lazyInit);
	boolean isLazyInit();
	
	
	/** 依赖关系。
		dependsOn 是当前bean依赖的其它bean的name。
		在getBean()中:合并BeanDefinition修改后,会先通过getBean()获取dependsOn依赖的实例,保证所有dependsOn依赖都已经实例化,再根据bean的scope调用createBean()创建bean实例 */
	void setDependsOn(@Nullable String... dependsOn);
	String[] getDependsOn();
	
	
	/** 自动装配时是否优先选用。
		有多个可用实例时,会优先使用primary为true的bean */
	void setPrimary(boolean primary);
	boolean isPrimary();
	
	
	//要使用的 FactoryBean 的name
	void setFactoryBeanName(@Nullable String factoryBeanName);
	String getFactoryBeanName();
	
	
	//要使用的 FactoryMethod 的name
	void setFactoryMethodName(@Nullable String factoryMethodName);
	String getFactoryMethodName();
	
	
	//构造器的参数表,包括参数名、参数类型、参数值
	ConstructorArgumentValues getConstructorArgumentValues();
	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}
	
	
	//属性值,包括属性名、属性值
	MutablePropertyValues getPropertyValues();
	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}
	
	
	//初始化方法
	void setInitMethodName(@Nullable String initMethodName);
	String getInitMethodName();
	
	
	//销毁方法
	void setDestroyMethodName(@Nullable String destroyMethodName);
	String getDestroyMethodName();
	
	
	//bean的角色,比如spring本身的bean、第三方框架的bean、开发自定义的bean
	void setRole(int role);
	int getRole();
	
	
	//bean的描述文字。对bean进行简单介绍,主要给其他开发看
	void setDescription(@Nullable String description);
	String getDescription();
	
	
	//一些判断方法。可以把抽象类标识为bean,但抽象类本身是不会实例化的。
	boolean isSingleton();
	boolean isPrototype();
	boolean isAbstract();
	
	
	//bean对应的Resource的描述信息
	String getResourceDescription();
	
	
	/** 获取原始的BeanDefinition。
		一个bean可以用多种方式共同配置,在加载过程中会合并BeanDefinition的修改,这个bean最先解析提取到的BeanDefinition即为原始BeanDefinition */
	BeanDefinition getOriginatingBeanDefinition();

}

 

beans模块的BeanFactory

BeanFactory是容器的顶级接口,定义IoC容器的基础功能,包括bean的创建、装配、获取、管理

 

context模块的ApplicationContext

spring加载资源、配置得到Resource,根据Resource创建Context。

context:背景、环境、上下文,融合了spring容器中的各种资源,开发者、第三方类库通过与context交互来操作spring容器、获取容器中的资源,相当于spring营造的的应用环境、spring对外暴露的util。

ApplicationContext 就是context模块中的。

 

spring的2大特性 | 核心

IoC 控制反转

IoC:Inversion of Control,控制反转,传统应用是由开发者在代码中控制对象的创建,IoC是将对象创建的控制权交给IoC容器,由IoC容器负责对象的创建、管理。
 

IoC的优点
  • 避免在各处使用new来创建实例,降低类之间的耦合度,易于维护
  • 由容器负责创建类的实例、注入所需依赖,开发者无需关心对象创建的细节、对象间复杂的依赖关系,简化了应用开发、降低了开发难度。

 

IoC常见的实现方式
  • DL:依赖查找,bean主动到IoC容器中查找所需的依赖
  • DI:Dependency Injection,依赖注入,由IoC容器主动给bean注入所需的依赖

DL是EJB时代的实现方式,现在主流的实现方式是DI

 

IoC、DI的关系

IoC是一种编程思想,DI是IoC的一种实现方式

 

spring IoC的实现机制

镜像问题

  • spring IoC的实现原理|机制
  • spring IoC是怎么实现的
     

核心点:工厂模式+反射机制+工厂方法

主要采用工厂模式实现,通过 BeanFactory 的 getBean() 方法获取所需实例,如果实例不存在,会调用 createBean() 主动创建所需实例。

创建实例可以使用构造方法方式,实质是通过反射机制调用构造方法创建实例;也可以通过工厂方法创建实例。

 

DI的实现原理

镜像问题:spring是如何实现DI的?

通过 getBean() 获取bean实例时,如果没有对应的实例,会调用 createBean() 创建bean实例。

在填充属性阶段,根据注入模式选择 autowireByName() 或 autowireByType() 进行注入,在注入过程中使用 getBean() 获取所需依赖。

 

AOP 面向切面编程

aop: Aspect-Oriented Programming 面向切面编程,是面向对象编程的一种补充, 在不改变原有业务逻辑的基础上添加额外的处理。
 

aop的优点

把和业务逻辑无关的横切逻辑剥离出来,不与业务代码耦合在一起,减少系统中的重复代码,使系统变得高内聚、低耦合,更易维护。

 

aop常见的应用场景
  • 记录日志、流水
  • 事务管理
  • 安全检查、权限控制
  • 更新缓存

 

aop中的主要名词|概念
  • Aspect:切面,横切逻辑的代码实现,通常是一个类,定义了切入点、通知
  • Advice:通知、增强,可以看做把切面按作用时机的划分
  • Target:目标,要应用切面的业务对象、类
  • JointPoint:连接点,目标类|对象中的所有方法都可以作为连接点
  • PointCut:切入点,目标类|对象中实际应用切面 | 切面的方法
  • Weaving:织入,把切面应用到连接点以实现增强的过程

 

aop的织入时机 | 方式
  • 编译时织入:通过修改编译生成的字节码实现,需要借助专门的编译器,缺点是编译就已确定要增强的对象、要应用的增强,不够灵活
  • 编译后织入:生成字节码之后、类加载之前,使用工具对字节码进行处理以应用增强
  • 类加载时织入:使用自定义的类加载器,在类加载时应用增强
  • 运行时织入:在运行时通过动态代理生成代理,使用代理代替目标对象进行操作

 

spring提供的2种aop实现

1、spring aop

spring早期版本提供的aop实现,只提供了简单的aop实现,局限多,只能对spring容器中的bean应用增强,只能对方法进行增强。
 

spring aop默认使用的代理策略、织入时机

  • spring aop基于动态代理实现,可以指定要使用的动态代理类型,在运行时进行织入
  • 未指定要使用的动态代理类型时,默认使用jdk动态代理,如果不满足jdk动态代理的使用条件(目标类没有实现接口),则使用cglib代理。
     

spring aop的实现原理

  • spring aop是基于动态代理实现的,在运行时动态生成代理
  • 默认使用jdk动态代理,如果目标没有实现接口,则使用cglib代理

 

2、aspectj

aspectj是一个专业的aop框架,提供了一套完整的aop解决方案,在spring的后续版本中集成aspectj。aspectj比spring aop更加强大,可对所有域中的对象进行增强,可对字段、方法、构造方法等内容进行增强。
 

aspectj的织入时机、原理

  • aspectj支持在编译时、编译后、类加载时进行织入
  • 通常使用编译时织入,需要借助AspectJ 编译器 (ajc) ,基于字节码操作,使用的是静态代理。
     

性能比较

  • aspectj通常使用编译时织入,在编译时就可以确定增强,使用时直接生成代理
  • spring aop是在运行时动态生成代理,性能比aspectj差,在大量使用aop的项目中性能差距尤其明显
     

aspectj的应用范围更广、性能更好,比spring aop更强大,更常用,也更推荐使用aspectj。

 

spring中的2个核心概念

bean

常见问题

  • java bean、spring bean的区别
  • 什么是spring bean
     
传统的java bean

简单来说就是实体类,用来封装对象,包含成员属性和对应的getter、setter方法。

 

spring bean

bean是spring中的核心概念,使用spring其实是面向bean编程,开发的主要任务就是编写、配置bean。

spring中的bean有2层含义

  • 可以看成 BeanDefinition 实例
  • 也可以看成由spring容器负责创建、装配、管理的 java 对象

 

容器

实现了IoC的容器都可以叫做IoC容器,spring容器只是IoC的一种实现,只是IoC容器中的一种,spring容器 ≠ IoC容器。

 

spring容器提供的功能
  • 依赖注入,这是最重要的功能
  • 自动装配
  • 可以设置回调方法,以及bean的初始化方法、销毁方法

 

spring中2种容器 | 容器的2个核心接口

相关问题:BeanFactory、ApplicationContext的联系与区别
 

BeanFactory

  • 功能:提供IoC容器的基础功能,负责创建bean实例、注入所需依赖,是获取bean实例的工厂、低级容器
  • 定位:面向spring框架本身,主要在spring框架内部使用
  • bean的实例化时机:低级容器启动时,不会实例化bean,调用getBean()从容器中获取bean实例时才会实例化对应的bean
  • 注册方式:支持 BeanPostProcessor、BeanFactoryPostProcessor ,但需要手动注册
     

ApplicationContext

  • 功能:在BeanFactory的基础上继承了多个接口,集成了更多功能,几乎包括了应用中的各种资源,是context 应用运行的环境、高级容器,而非简单的获取bean实例的工厂
  • 定位:面向spring的使用者,主要提供给spring的使用者进行调用
  • bean的实例化时机:高级容器启动时,会实例化所有单例(懒加载的单例除外),这也造成了高级容器启动速度比低级容器慢得多
  • 注册方式:支持 BeanPostProcessor、BeanFactoryPostProcessor ,高级容器启动时会自动注册
     

一般把 BeanFactory 称为低级容器、IoC 容器,把 ApplicationContext 称为应用上下文、高级容器,通常说的Spring容器是指高级容器 ApplicationContext 。

 

spring容器的实现原理

镜像问题

  • spring是怎么实现容器的
  • spring是如何设计容器的
  • spring容器的实现机制 | 原理
     

spring提供了2个容器

  • BeanFactory:低级容器,实现了容器的基础功能IoC,负责bean实例的创建、依赖注入
  • ApplicationContext:高级容器,在BeanFactory的基础上集成了更丰富的功能,是整个应用的运行环境、上下文。

DefaultListableBeanFactory整合了BeanFactory体系的主要接口,功能齐全,常作为低级容器的实现。

AbstractApplicationContext 实现了加载|刷新配置的 refresh() 方法,是 ApplicationContext 的主要实现类,也是高级容器最终实现类的共同基类。

高级容器中内置了低级容器,通过内置的低级容器提供IoC容器的基础功能。

 

spring中用到的设计模式

  • 工厂模式:通过BeanFactory创建bean实例
  • 单例模式:bean默认是单例的
  • 代理模式:spring aop通过动态代理实现
  • 模板方法:抽取特定场景中经常复用的代码,解决重复代码多的问题,比如JdbcTemplate、RestTemplate, JmsTemplate, JpaTemplate
  • 观察者模式:主题对象的状态发生改变时,通知订阅了该主题的所有对象,Spring的事件驱动模型(listener 监听器)就是观察者模式的经典应用。
  • 适配器模式:比如springmvc中的处理器适配器 HandlerAdapter,spring aop中用于适配Advice的AdviceAdapter
  • 策略模式
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值