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