spring 总结
2020-06-10 23:23:17 58 举报
AI智能生成
登录查看完整内容
spring 总结
作者其他创作
大纲/内容
spring
核心思想(IOC&AOP)
IOC 解决了对象依赖的问题,控制权交给工厂
IoC和DI的区别
IOC和DI描述的是同⼀件事情,只不过⻆度不⼀样罢了。IOC 是将对象管理交给工厂DI是把对象依赖的其他类的属性注入进去。例如:针对A类声明的B类属性,就需要将B类注入到A
AOP⾯向切⾯编程 是OOP的延续,在不改变原有业务逻辑情况下,增强横切逻辑代码OOP编程思想可以解决⼤多数的代码重复问题,但是有⼀些情况是处理不了的。比如对所有代码增加事务,就是一种横切逻辑代码。
自定义IOC&AOP框架
dao层以及service层对数据依赖,从对实现类的实例化 改成 注入接口写法,减少依赖(只要需要实例化创建的都可以交给BeanFactory去反射创建)
创建bean.xml,设置需要实例化的对象,以及依赖关系
创建BeanFactory.java,解析xml中的对象全限定名,反射创建存入map中
编写ConnectionUtils 工具类,将数据库链接存入 本地缓存,保证进行数据库操作走同一连接,可以进行事务控制
创建TransactionManager 事务管理器工具类
创建ProxyFactory代理工厂类,使用JDK动态代理对要执行的业务方法,进行事务增强
创建TransferServlet 请求处理类,getBean获取ProxyFactory实例。对请求进来要调用的方法调用 ProxyFactory进行动态代理,对 数据库操作进行事务控制。
IOC应用
基础
BeanFactory与ApplicationContext区别
BeanFactor是顶级接口,定义基础功能规范,ApplicationContext 是高级接口,具备BeanFactory全部功能。具体区别如下:继承 org.springframework.context.MessageSource 接口,提供国际化的标准访问策略。继承 org.springframework.context.ApplicationEventPublisher 接口,提供强大的事件机制。扩展 ResourceLoader ,可以用来加载多种 Resource ,可以灵活访问不同的资源。对 Web 应用的支持。
启动 IoC 容器的⽅式
java环境
ClassPathXmlApplicationContext:从类的根路径下加载配置⽂件(推荐使⽤)FileSystemXmlApplicationContext:从磁盘路径上加载配置⽂件AnnotationConfigApplicationContext:纯注解模式下启动Spring容器
web环境
实例化Bean的三种⽅式
使⽤⽆参构造函数使⽤静态⽅法创建使⽤实例化⽅法创建
Bean的X及⽣命周期
作用范围&生命周期
单例模式:singleton对象出⽣:当创建容器时,对象就被创建了。对象活着:只要容器在,对象⼀直活着。对象死亡:当销毁容器时,对象就被销毁了。⼀句话总结:单例模式的bean对象⽣命周期与容器相同。
多例模式:prototype对象出⽣:当使⽤对象时,创建新的对象实例。对象活着:只要对象在使⽤中,就⼀直活着。对象死亡:当对象⻓时间不⽤时,被java的垃圾回收器回收了。⼀句话总结:多例模式的bean对象,spring框架只负责创建,不负责销毁。
标签属性
id、class、name...
依赖注入xml配置 : set、构造器注入...
配置模式:纯注解&注解+xml& xml
高级特性
lazy-Init 延迟加载提高容器启动和运转性能
FactoryBean 和 BeanFactory
BeanFactory接⼝是容器的顶级接⼝,定义了容器的⼀些基础⾏为,负责⽣产和管理Bean的⼀个⼯⼚,具体使⽤它下⾯的⼦接⼝类型,⽐如ApplicationContext;
实现FactoryBean接口 它⾃定义Bean的创建过程。如果要获取FactoryBean,需要在id之前添加“&”
后置处理器
BeanPostProcessor是针对Bean级别的处理,可以针对某个具体的Bean注意:处理是发⽣在Spring容器的实例化和依赖注⼊之后。
BeanFactory级别的处理,是针对整个Bean的⼯⼚进⾏处理,典型应⽤:PropertyPlaceholderConfigurerBeanDefinition对象:我们在 XML 中定义的 bean标签,Spring 解析 bean 标签成为⼀个 JavaBean,这个JavaBean 就是 BeanDefinition注意:调⽤ BeanFactoryPostProcessor ⽅法时,这时候bean还没有实例化,此时 bean 刚被解析成BeanDefinition对象
IOC源码深度剖析
Spring IoC容器初始化主体流程
IoC容器体系
IoC容器是Spring的核⼼模块,是抽象了对象管理、依赖关系管理的框架解决⽅案。Spring IoC 容器继承体系需要使⽤哪个层次⽤哪个层次即可。不是把所有接口都放在BeanFactoryApplicationContext 还继承了ResourceLoader、MessageSource
Bean⽣命周期关键时机点
详细见代码。创建⼀个类 Bean ,让其实现⼏个特殊的接⼝,并分别在接⼝实现的构造器、接⼝⽅法中断点,观察线程调⽤栈,分析出 Bean 对象创建和管理关键点的触发时机。
根据上⾯的调试分析,我们发现 Bean对象创建的⼏个关键时机点代码层级的调⽤都在AbstractApplicationContext 类 的 refresh ⽅法中,可⻅这个⽅法对于Spring IoC 容器初始化来说相当关键,汇总如下:构造器 - refresh#finishBeanFactoryInitialization(beanFactory)(beanFactory)BeanFactoryPostProcessor 初始化refresh#invokeBeanFactoryPostProcessors(beanFactory)BeanFactoryPostProcessor ⽅法调⽤refresh#invokeBeanFactoryPostProcessors(beanFactory)BeanPostProcessor 初始化registerBeanPostProcessors(beanFactory)BeanPostProcessor ⽅法调⽤refresh#finishBeanFactoryInitialization(beanFactory)
子主题
IoC容器初始化主流程(refresh)
第⼀步:刷新前的预处理 prepareRefresh();
第⼆步:获取BeanFactory;默认实现是DefaultListableBeanFactory加载BeanDefition 并注册到 BeanDefitionRegistryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
第三步:BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加载器等)prepareBeanFactory(beanFactory);
第四步:BeanFactory准备⼯作完成后进⾏的后置处理⼯作postProcessBeanFactory(beanFactory);
第五步:实例化并调⽤实现了BeanFactoryPostProcessor接⼝的BeaninvokeBeanFactoryPostProcessors(beanFactory);
第六步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执⾏registerBeanPostProcessors(beanFactory);
第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);initMessageSource();
第⼋步:初始化事件派发器initApplicationEventMulticaster();
第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑onRefresh();
第⼗步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器beanregisterListeners();
第⼗⼀步:初始化所有剩下的⾮懒加载的单例bean初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)填充属性初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、init-method⽅法)调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处finishBeanFactoryInitialization(beanFactory);
第⼗⼆步:完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事件 (ContextRefreshedEvent)finishRefresh();
BeanFactory创建流程
获取BeanFactory⼦流程
BeanDefinition加载解析及注册⼦流程
Resource定位:指对BeanDefinition的资源定位过程。通俗讲就是找到定义Javabean信息的XML⽂件,并将其封装成Resource对象。
BeanDefinition载⼊ :把⽤户定义好的Javabean表示为IoC容器内部的数据结构,这个容器内部的数据结构就是BeanDefinition。
Bean创建流程
lazy-init 延迟加载机制原理
lazy-init 延迟加载机制分析
Spring 启动的时候会把所有bean信息(包括XML和注解)解析转化成Spring能够识别的BeanDefinition并存到Hashmap⾥供下⾯的初始化时⽤,然后对每个BeanDefinition 进⾏处理。如果是懒加载的则在容器初始化阶段不处理,其他的则在容器初始化阶段进⾏初始化并依赖注⼊。最后通过外部getBean调用。preInstantiateSingletons() 下 !bd.isLazyInit() 判断懒加载,是否需要初始化。普通Bean 直接调用getBean
总结
对于被修饰为lazy-init的bean Spring 容器初始化阶段不会进⾏ init 并且依赖注⼊,当第⼀次进⾏getBean时候才进⾏初始化并依赖注⼊对于⾮懒加载的bean,getBean的时候会从缓存⾥头获取,因为容器初始化阶段 Bean 已经初始化完成并缓存了起来
Spring IoC循环依赖问题
什么是循环依赖
解释:循环依赖其实就是循环引⽤,也就是两个或者两个以上的 Bean 互相持有对⽅,最终形成闭环。⽐如A依赖于B,B依赖于C,C⼜依赖于A。
Spring中循环依赖场景有1.构造器的循环依赖(构造器注⼊) 2.Field 属性的循环依赖(set注⼊)构造器的循环依赖问题⽆法解决,只能拋出 BeanCurrentlyInCreationException 异常,在解决属性循环依赖时,spring采⽤的是提前暴露对象的⽅法。
循环依赖处理机制
分析:单例 bean 构造器参数循环依赖(⽆法解决)prototype 原型 bean循环依赖(⽆法解决)对于原型bean的初始化过程中不论是通过构造器参数循环依赖还是通过setXxx⽅法产⽣循环依赖,Spring都 会直接报错处理。Spring 的循环依赖的理论依据基于 Java 的引⽤传递,当获得对象的引⽤时,对象的属性是可以延后设置的,但是构造器必须是在获取引⽤之前
解决流程:(涉及到使用三级缓存)二级缓存的作用-> 升级过程中可以完成一些扩展操作Spring容器初始化ClassA通过构造器初始化对象后提前暴露到Spring容器。(将A放入三级缓存中,暴露自己)ClassA调⽤setClassB⽅法,Spring⾸先尝试从容器中获取ClassB,此时ClassB不存在Spring容器中。(从三级缓存中取A)Spring容器初始化ClassB,同时也会将ClassB提前暴露到Spring容器中(将A提到二级缓存中)ClassB调⽤setClassA⽅法,Spring从容器中获取ClassA ,因为第⼀步中已经提前暴露了ClassA,因此可以获取到ClassA实例ClassA通过spring容器获取到ClassB,完成了对象初始化操作。(完成后将A提到二级缓存中)这样ClassA和ClassB都完成了对象初始化操作,解决了循环依赖问题。(B创建完放入一级缓存,A直接从一级缓存取)
Spring AOP 应⽤
术语
Joinpoint(连接点) 就是需要增强的方法
Pointcut(切⼊点) 已经把增强代码加⼊到业务主线进来之后的连接点
Advice(通知/增强) 切⾯类中⽤于提供增强功能的⽅法。其分类有:前置通知 后置通知 异常通知 最终通知 环绕通知
Target(⽬标对象) 被代理对象
Proxy(代理) 代理对象
Weaving(织⼊) 把增强应⽤到⽬标对象来创建新的代理对象的过程。spring采⽤动态代理织⼊,⽽AspectJ采⽤编译期织⼊和类装载期织⼊。
Aspect(切⾯) 增强的代码所关注的⽅⾯ TrasnactionManager 就是⼀个切⾯
总结 : Aspect切⾯= 切⼊点+增强= 切⼊点(锁定⽅法) + ⽅位点(锁定⽅法中的特殊时机)+ 横切逻辑
Spring中AOP的代理选择
JDK
CGLIB
Spring中AOP的配置⽅式
第⼀类:使⽤XML配置第⼆类:使⽤XML+注解组合配置第三类:使⽤纯注解配置
Spring中AOP实现
注意细节: 1. pointcut 全限定⽅法名 访问修饰符 返回值 包名.包名.包名.类名.⽅法名(参数列表)2. 改变代理⽅式的配置 <aop:config proxy-target-class=\"true\">3. 使⽤aop:aspectj-autoproxy标签配置 <!--此标签是基于XML和注解组合配置AOP时的必备标签,表示Spring开启注解置AOP的⽀持--> <aop:aspectj-autoproxy proxy-target-class=\"true\"></aop:aspectjautoproxy>4. <!--开启spring对注解aop的⽀持--> <aop:aspectj-autoproxy/>
Spring 声明式事务的⽀持
编程式事务:在业务代码中添加事务控制代码,这样的事务控制机制就叫做编程式事务声明式事务:通过xml或者注解配置的⽅式达到事务控制的⽬的,叫做声明式事务
事务的四⼤特性
原⼦性(Atomicity)⼀致性(Consistency)隔离性(Isolation)持久性(Durability)
事务的隔离级别
数据库共定义了四种隔离级别: Serializable(串⾏化):可避免脏读、不可重复读、虚读情况的发⽣。(串⾏化) 最⾼Repeatable read(可重复读):可避免脏读、不可重复读情况的发⽣。(幻读有可能发⽣) 第⼆该机制下会对要update的⾏进⾏加锁Read committed(读已提交):可避免脏读情况发⽣。不可重复读和幻读⼀定会发⽣。 第三Read uncommitted(读未提交):最低级别,以上情况均⽆法保证。(读未提交) 最低
事务的传播⾏为
PROPAGATION_REQUIRED 如果当前没有事务,就新建⼀个事务,如果已经存在⼀个事务中,加⼊到这个事务中。这是最常⻅的选择。
PROPAGATION_SUPPORTS ⽀持当前事务,如果当前没有事务,就以⾮事务⽅式执⾏。
Spring中事务的API
PlatformTransactionManager
Spring 声明式事务配置
配置代码 略
Spring AOP源码深度剖析
准备测试用例 (代码略)
时机点分析
在测试用例getBean断点,找到 applicationContext ->BeanFactory -> singletonObjects
在 getBean 之前,LagouBean对象已经产⽣(即在第⼀⾏初始化代码中完成),⽽且该对象是⼀个代理对象(Cglib代理对象),我们断定,容器初始化过程中⽬标Bean已经完成了代理,返回了代理对象。
代理对象创建流程
AbstractAutowireCapableBeanFactory#initializeBean (初始化Bean)
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization(整个Bean初始化完成,执⾏后置处理器⽅法)
AbstractAutoProxyCreator#postProcessAfterInitialization (各种检查)
AbstractAutoProxyCreator#wrapIfNecessary (得到所有候选Advisor,对Advisors和bean的⽅法双层遍历匹配,最终得到⼀个List<Advisor>,即specificInterceptors 创建代理对象)
AbstractAutoProxyCreator#createProxy (为指定 bean 创建代理对象)
ProxyFactory#getProxy (创建代理的⼯作交给ProxyFactory)
ProxyFactory#getProxy-- CglibAopProxy#getProxy (设置proxyTargetClass=true强制使⽤Cglib 代理)
Spring声明式事务控制
@EnableTransactionManagement @Transactional
概要
@EnableTransactionManagement使⽤ @Import 标签引⼊了TransactionManagementConfigurationSelector类又引入了 :AutoProxyRegistrarProxyTransactionManagementConfiguration
加载事务控制组件
AutoProxyRegistrar
AutoProxyRegistrar#registerBeanDefinitions
AopConfigUtils.registerAutoProxyCreatorIfNecessary
InfrastructureAdvisorAutoProxyCreator(AbstractAutoProxyCreator 的⼦类)
它实现了SmartInstantiationAwareBeanPostProcessor,说明这是⼀个后置处理器,⽽且跟spring AOP 开启@EnableAspectJAutoProxy 时注册的 AnnotationAwareAspectJProxyCreator实现的是同⼀个接⼝,所以说,声明式事务是 springAOP 思想的⼀种应⽤
ProxyTransactionManagementConfiguration
ProxyTransactionManagementConfiguration是⼀个容器配置类,注册了⼀个组件transactionAdvisor,称为事务增强器,然后在这个事务增强器中⼜注⼊了两个属性:transactionAttributeSource,即属性解析器transactionAttributeSource 和 事务拦截器transactionInterceptor
AnnotationTransactionAttributeSource的属性解析器有⼀个成员变量是annotationParsers,是⼀个集合,可以添加多种注解解析器。属性解析器的作⽤之⼀就是⽤来解析@Transaction注解
TransactionInterceptor 事务拦截器
流程记录
@EnableTransactionManagement 注解1)通过@import引⼊了TransactionManagementConfigurationSelector类它的selectImports⽅法导⼊了另外两个类:AutoProxyRegistrar和ProxyTransactionManagementConfiguration2)AutoProxyRegistrar类分析⽅法registerBeanDefinitions中,引⼊了其他类,通过AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)引⼊InfrastructureAdvisorAutoProxyCreator,它继承了AbstractAutoProxyCreator,是⼀个后置处理器类3)ProxyTransactionManagementConfiguration 是⼀个添加了@Configuration注解的配置类(注册bean)注册事务增强器(注⼊属性解析器、事务拦截器)属性解析器:AnnotationTransactionAttributeSource,内部持有了⼀个解析器集合Set<TransactionAnnotationParser> annotationParsers;具体使⽤的是SpringTransactionAnnotationParser解析器,⽤来解析@Transactional的事务属性事务拦截器:TransactionInterceptor实现了MethodInterceptor接⼝,该通⽤拦截会在产⽣代理对象之前和aop增强合并,最终⼀起影响到代理对象TransactionInterceptor的invoke⽅法中invokeWithinTransaction会触发原有业务逻辑调⽤(增强事务)
0 条评论
回复 删除
下一页