Spring 知识
2020-09-10 17:14:28 0 举报
AI智能生成
Spring知识结构,源码方法分析,没有比这个更全更详细的Spring知识结构
作者其他创作
大纲/内容
基本概念
Spring 优点
轻量级,非侵入式
对现有的类和结构没有影响
可以提供众多服务,如事务管理,WS(Web Service)等
AOP的很好支持,方便面向切面编程,使得业务逻辑和系统服务分开
对主流的框架提供了很好的集成支持,如hibernate,Struts2,JPA等,像一个胶水一样,把一些好的框架粘合到一起方便使用
使用Spring的IOC容器,将对象之间的依赖关系交给Spring,降低组件之间的耦合性,让我们更专注于应用逻辑
Spring DI机制降低了业务对象替换的复杂性
Spring 的高度可开放性能,并不强制依赖于Spring, 开发者可以自由选择Spring部分或全部
Spring 缺点
缺少一个公用控制器
没有SpringBoot好用
Spring像一个胶水,将框架粘合到一起,后面拆分的话就不容易拆分了
AOP
基本概念
核心业务功能和切面功能分别独立进行开发,然后把切面功能和核心业务功能“编织”在一起,这就叫AOP
让关注点代码与业务代码分离
面向切面编程就是指:对很多功能都有的重复代码的抽取,再在运行的时候往业务方法上动态植入“切面类代码”
应用场景:日志, 事务管理,权限管理
实现原理
jdk动态代理
主要通过:Proxy.newProxyInstance() 和 InvocationHandler 这两个类和方法实现
实现过程
创建代理类Proxy实现Invocation接口, 重写invoke() 方法
调用被代理类方法时默认调用此方法
将被代理类作为构造函数的参数传入代理类Proxy
调用Proxy.newProxyInstance(classloader, interfaces, handler)方法生成代理类
生成的代理类
$Proxy() extends Proxy implements Preson
类型为 $Proxy()
因为Proxy已经继承了Proxy,所以java动态代理只能对接口进行代理
代理对象会实现用户提供的这组接口,因此可以将这个代理对象强制类型转换为这组接口中的任意一个
通过反射生成对象
总结:使用代理类调用自己方法时,通过自身特有的中介类对象来调用中介类对象的invoke()方法,从而达到代理执行被代理对象的方法。
cglib
生成对象类型为:Enhancer
实现原理类似于JDK动态代理,只是他在运行期间生成的代理对象是针对目标类扩展的子类
Spring 在运行期间通过CGlib 继承要被动态代理的类,重写父类的方法,实现AOP面向切面编程
静态代理
缺点
如果要代理一个接口的多个实现的话,需要定义不同的代理类
代理类 和 被代理类 必须实现同样的接口,万一接口有变动,代理、被代理类都得以修改,难以维护
在编译的时候就直接生成代理类
JDK动态代理和cglib的对比
CGLib 所创建的动态代理对象在实际运行时候的性能要比JDk动态代理高
1.6 和 1.7的时候,CGLib 更快
1.8 JDK更快
CGLib 在创建对象的时候所花费的时间却比JDK动态代理多
singleton的代理对象或者具有实例池的代理,因为无需频繁的创建代理对象,所以比较适合采用CGLib动态代理,反之,则适合JDK动态代理
JDK动态代理是面向接口的,CGLib动态代理是通过字节码底层继承代理类来实现(如果被代理类被final关键字修饰,则会失败)
JDK生成的代理类类型是Proxy(因为继承的是Proxy), CGLi生成的代理类型是Enchanter类型
如果要被代理的对象是个实现类,那么Spring会使用JDK动态代理来完成操作(Spring默认采用JDK动态代理实现机制)
如果要被代理的对象不是实现类,那么Spring会强制使用CGLib来实现动态代理
配置方式
XML方式
注解方式
基于Java类配置
通过 @Configuration 和 @Bean 这两个注解实现的
@Configuration 作用于类上,相当于xml配置文件
@Bean 作用于方法上,相当于xml配置中的<Bean>
IOC
依赖注入(DI)
装配方式(依赖注入的具体行为)
基于注解的自动装配
实现方式
注解
@Autowired
1.优先按照byType方式进行查找
2.如果查询结果不止一个,而且没有设置名称的话,那么会报错
3.否则@Autowired会按照byName方式查找
4.如果查询结果为空,那么会抛出异常。可以使用required=false解决
@Resource
1.默认按照byName方式进行装配,名称可以通过name属性进行指定
2.如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名行装配
3.当找不到与名称匹配的bean时,才通过byType进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
4.只指定@Resourse注解的type属性,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
自动扫描(component-scan)
便签将会开启Spring Bean的自动扫描,并可设置base-package属性,表示Spring将会扫描该目录以及子目录下所有被@Component标识修饰的类,对它们进行装配
基于XML配置的显示装配
基于Java配置的显示装配
能够在编译时就发现错误
依赖注入的方法
构造方法注入
构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖
使用构造器注入的好处
1.保证依赖不可变(final关键字)
2.保证依赖不为空
实例化Controller的时候,由于自己实现了有参数的构造函数,所以不会提供无惨构造函数,那么就需要Spring容器传入所需要的参数,这样就保证了依赖不为空
3.避免循环依赖
在构造器注入传入参数时,比如在A中注入B,在B中注入A。就先初始化A,那么需要传入B,这个时候发现需要B没有初始化,那么就要初始化B,这个时候就出现了问题,会排除循环依赖错误,而是用filed注入方式则只能在运行时才会遇到这个问题
setter方法注入
通过找到类对应的setter方法,在进行相应的注入
Setter方法注入是容器通过调用无参构造器或无参static工厂方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入
最好的解决方案是用构造器参数实现强制依赖,setter方法实现可选依赖
构造器方式无法解决,只能抛出异常
因为加入singletonFactories三级缓存的前提是执行了构造器(因为要先构建出对象),所以构造器的循环依赖没法解决
多例方式无法解决,只能抛出异常
因为Spring容器不缓存“prototype”作用域的bean,因此无法提前暴露一个创建中的bean
单例模式可以解决
通过三级缓存解决
在createBeanInstance() 之后会调用addSingeton()方法将bean注册到singletonFactories中
通过提前暴露一个单例工厂方法,从而使其他bean能够引用到该bean/提前暴露一个正在创建中的bean
举例
1.“A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”
2. A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中(关键)
3.A发现自己依赖对象B,此时就会尝试去get(B),发现B还没有被create,所以走create流程
4,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没有初始化完全),尝试二级缓存earlySingletonObjeacts(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObect()拿到对象A
5.B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中
6.返回A中,A此时能拿到B的对象顺利完成了自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects
7.由于B拿到了A的对象引用,所以B中的A对象完成了初始化
Spring 容器
BeanFactory
HierarchicalBeanFactory
ListableBeanFactory
定义访问容器基本信息的方法
获取Bean的个数
获取某一类型Bean的配置信息
查看容器中是否包含某一Bean的信息
AutowireCapableBeanFactory
ConfigurableBeanFactory
ConfigurableListableBeanFactory
AbstractBeanFactory
AbstractAutowireCapableBeanFactory
DefaultListableBeanFactory
ApplicationContext
继承的接口
MessageSource
国际化
ApplicationEventPublisher
时间发布
EnvironmentCapable
环境管理
ResourceLoader
资源加载
FileSystemResourse
AbstractFileResolvingResourse
ByteArrayResourse
BeanDefinitionResourse
InpoutreamResourse
UrlResource
ClassPathResourse
ServletContextResource
BeanFactory
Bean 的管理
非Web系列
ConfigurableApplicationContext
AbstractApplicationContext
AbstractRefreshableApplicationContext
AbstractRefreshableConfigApplicationContext
AbstactXmlApplicationContext
GenericApplicationContext
AnnotationConfigApplicationContext
Web系列
ConfigurableWebApplicationContext
AbstractRefreshableWebApplicationContext
XmlWebApplicationContext
GenericWebApplicationContext
父子容器
容器扩展节点
BeanFactoryPostProcessor
FactoryBean
BeanPostProcessor
Spring Bean
bean 的生命周期
1.Bean元信息配置阶段
2.Bean元信息解析阶段
3.将Bean注册到容器中
4.BeanDefinition合并阶段
5.Bean Class加载阶段
6.Bean实例化阶段
Bean实例化前 阶段
Bean实例化阶段
7.合并后的BeanDefinition处理
8.属性值阶段
Bean实例化后阶段
Bean属性赋值前阶段
9.Bean初始化阶段
Bean Aware接口回调阶段
Bean 初始化前阶段
Bean 初始化阶段
Bean 初始化后阶段
10.所有单例Bean初始化完成后阶段
11.Bean的使用阶段
12.Bean的销毁前阶段
13.Bean的销毁阶段
BeanDefinition
RootBeanDefinition
表示根Bean定义信息,通常Bean中没有父Bean的就使用这种表示
ChildBeanDefinition
表示子Bean定义信息,如果需要指定父Bean的,可以使用ChildBeanDefinition来定义Bean的配置信息,里面有一个parentName属性,用来指定父Bean的名称
GenericBeanDefinition
通用的Bean定义信息,既可以表示没有父Bean的Bean配置信息,也可以表示有父Bean的Bean配置信息,这里面也有parentName属性,用来指定父Bean的名称
AnnotatedBeanDefinition
表示通过注解的方式定义Bean的信息
BeanDefinitionBuilder
构建BeanDefinition的工具类
BeanDefinition中的属性
ParentName
父BeanDefinition
BeanClassName
对应的Bean的ClassName
Scope
Bean的作用域,不考虑web容器,主要有两种:单例/原型
LazyInit
是否进行懒加载
DependsOn
是否需要等待指定的Bean创建完之后创建
AutowireCandidate
是否作为在自动注入的候选对象
Primary
是否作为主选的Bean
FactoryBeanName
创建这个Bean的类的名称
FactoryMethodName
创建这个Bean的方法的名称
ConstructorArgumentValues
构造方法的参数
PropertyValues
setter方法的参数
InitMethodName
生命周期回调方法,在Bean完成属性注入后调用
DestoryMethodName
生命周期的回调方法,在Bean被销毁时调用
Role
角色
Description
Bean的描述,没有什么实际含义
isSingleton
是否单例
isPrototype
是否原型
isAbstract
跟合并beanDefinition相关,如果是abstract,说明会被作为一个父beanDefinition,不提供class属性
ResourceDescription
bean的源描述,没有什么实际意义
OriginatingBeanDefinition
cglib代理前的BeanDefinition
Bean的作用域
singleton
Spring IoC 容器中只会存在一个共享的 Bean 实例,无论有多少个
Bean 引用它,始终指向同一对象
Bean 引用它,始终指向同一对象
线程不安全
显示定义:<bean id="userDao" class="com.ioc.UserDaoImpl" scope="singleton"/>
prototype
每次通过 Spring 容器获取 prototype 定义的 bean 时,容器都将创建
一个新的 Bean 实例,每个 Bean 实例都有自己的属性和状态
一个新的 Bean 实例,每个 Bean 实例都有自己的属性和状态
request
一次 Http 请求中,容器会返回该 Bean 的同一实例
不同的Http请求会产生不同的bean,该bean只会在当前的Http请求中生效
session
一次Http session中,会产生一次bean实例
不同的http session中会产生不同的bean实例,且仅在当前生效
不同的实例之间不共享
application
事务管理
基本概念
如果需要某一组操作具有原子性,就用注解的方式开启事务,按照给定的事务规则来执行提交或者回滚操作
事务控制
编程式事务控制
用户通过代码的形式手动控制事务
Conn.setAutoCommite(false); // 设置手动控制事务
声明式事务
Spring 提供对事务控制的控制管理
XML方式
注解方式
事务属性
事务传播行为
required_new
如果当前方法有事务了,当前方法事务会挂起,在为加入的方法开启一个新的事务,直到新的事务执行完,当前方法的事务才开始
required(默认方法)
如果当前方法已经有了事务,当加入当前方法事务
其余五种
事务传播行为用来描述有某一个事务传播行为修饰的方法被嵌套进另一个方法的时候事务如何传播
数据库隔离级别
TransactionDefinition.ISOLATION_DEFAULT
使用后端数据库默认的隔离级别,MySQL默认采用的REPEATABLE_READ隔离级别, Oracle默认采用的READ_COMMITTED隔离级别
TransactionDefinition.ISOLATION_READ_UNCOMMITTED
最低隔离级别,允许读取尚未提交的数据变更,可能导致脏读,幻读或不可重复读
TransactionDefinition.ISOLATION_READ_COMMITTED
允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读热有可能发生
TransactionDefinition.ISOLATION_REPEATABLE_READ
对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但是幻读仍有可能发生
TransactionDefinition.ISOLATION_SERIALIZABLE
最高的隔离级别,完全服从ACID的隔离级别。所有的事务一次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读,不可重复读以及幻读。但是这将严重影响程序的性能。通常情况用不到改级别
事务超时属性
指一个事务所允许执行的最长时间,如果超过该时间限制但是事务还没有完成,则自动回滚事务
事务只读属性
对事务资源是否执行只读操作
回滚规则
定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚,也可以用用户自己定义
Spring事务管理接口
PlatformTransactionManager
(平台)事务管理器
Spring并不直接管理事务,而且提供了很多种事务管理器,通过PlatformTransactionManager这个接口,Spring为各个平台如JDBC,Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事了
TransactionDefinition
事务定义属性(事务隔离级别、传播行为、超时、只读、回滚原则)
TransactionStatus
事务运行状态
事务管理一般在Service层
如果在dao层,回滚的时候只能回滚到当前方法,但一般我们的service层的方法都是有很多dao层的方法组成的
如果在dao层,commit的次数会多
相关的设计模式
1.单例模式
Spring依赖注入Bean实例默认是单例的
2.工厂模式
静态工厂
beanFactory
工厂模式
factoryBean
3.代理模式
AOP中的JDK动态代理和CGLib
4.适配器模式
实现方式
SpringMVC中的适配器HandlerAdapter
实现原理
HandlerAdapter根据Handler规则执行不同的Handler
5.装饰者模式
Spring中用到的包装器模式在类名上有两种表现
类名中含有:Wrapper
类名中含有Decorator
6.观察者模式
实现方式
Spring 中的事件驱动使用的是:观察者模式,Spring中Observe模式常用的地方是Listener的实现
具体实现
事件机制的实现需要三个部分:事件源,事件,事件监听器
7.策略模式
Spring框架的资源访问Resource接口。改接口提供了更强的资源访问能力,Spring框架本身大量使用了Resource接口来访问底层资源
Spring MVC
Spring MVC介绍
基于注解的控制器
转换和格式化
数据绑定和表单标签库
验证器
转换器和格式化
表达语言
JSTL
国际化
上传文件
下载文件
0 条评论
下一页