《Spring 揭秘》读书笔记
部分书中代码实现
事务部分
1. TransactionTemplate使用Connection怎么获取datasource的连接
如果使用最原生的import java.sql.Connection、datasource,在重写TransactionCallbackWithoutResult()的doInTransaction方法的时候需要通过DataSourceUtils.getConnection(dataSource)来获取连接,而不能直接datasource.getConnection()。主要是DataSourceUtils是从TransactionSynchronizationManager中获取的连接,而datasource.getConnection()是新建一个连接。transactionTemplate.execute()方法中会先进行transactionManager.getTransaction(),在这个方法里面会进行绑定TransactionSynchronizationManager。然后然后再调用doInTransaction方法,也就是复写的方法,然后绑定之后就可以通过DataSourceUtils.getConnection(dataSource)来获取。
2. TransactionSynchronizationManager是啥
里面包含了一堆ThreadLocal,包含这个线程下面的连接的一些信息,包括Transactional resources(datasource)、Transaction synchronizations、Current transaction name、Current transaction read-only status、Current transaction isolation level、Actual transaction active。里面提供了绑定数据源,解绑等操作。
3. 使用TransactionFacade将业务与事务管理相关代码抽象
TransactionFacade属于一个外观模式。如,A类有一个方法A(methodA),B类有一个方法B(methodB)。然后创建一个facade类,包含属性A,B,提供方法domethodA()其中调用A方法、domethodB()其中调用B方法。引用到这里就是使用一个TransactionFacade,里面提供两个方法,一个采用事务的方法txService()方法开始时候开始一个事务,业务代码结束之后提交事务;一个采用非事务方式,直接调用业务代码。示意图如下:
4. @Transaction原理
如果使用注释@Transaction,用于分离事务管理代码和业务代码(例子可以看使用TransactionTemplate进行事务管理例子),业务管理代码去获取有@Transaction注释的method,然后创建要给TransactionTemplate,根据@Transaction的属性设置去设置这个TransactionTemplate,最后调用transactionTemplate.execute(),在execute中调用业务代码。
IOC部分
1. 关于Component注入时候的bean名称问题
根据java.beans.Introspector.decapitalize中的命名规则,注入的bean如果开头两个是大写,就返回原类目,不然就把开头字母变小写,具体代码如下。这就是为什么@Component
写在类NewsProvider
上面时候不能直接用.getBean("NewsProvider")
获取的原因。当然也可以加别名@Component("NewsProvider")
。至于原书上面,他的类名是FXNewsProvider
开头两个字母是大写,自然没有这个问题。
public static String decapitalize(String name) {if (name == null || name.length() == 0) {return name;}if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&Character.isUpperCase(name.charAt(0))){return name;}char chars[] = name.toCharArray();chars[0] = Character.toLowerCase(chars[0]);return new String(chars);
}
2. 为什么注册的过程可以将BeanDefinition注册到BeanFactory后再配置依赖等。
因为注册的过程中只是将BeanDefinition放到BeanFactory的beanDefinitionMap中而真正初始化是在getBean()
的时候,这也就是为什么BeanFactory默认是懒加载机制。而如果在配置依赖之前,就getBean()
也就无法初始化Bean。
3. depends-on的疑惑
为什么不加depends-on就不会实例化那个依赖的对象。因为就像2所说的用xml只是注册绑定bean并没有真正的实例化bean,所以如果没有depends-on,也就不会实例化了。
4. 使用org.springframework.beans.factory.config.CustomEditorConfigurer来自定义propertyEditer
spring高版本中,将传入的map从原本的<Class,?>
改为了<Class,Class<? extends PropertyEditor>>
也就是说原本的value是先实例化后的,现在无法实例化了,因为我的PropertyEditor实现类没有无参构造函数。所以这个方法不可行。需要采用实现PropertyEditorRegistrar
类的方式,override的registerCustomEditors
这个函数入参提供的方法存在Class,PropertyEditor形式可以直接实例化自定义的propertyEditer
代码可以看重写propertyediter部分和registrar部分、配置bean的xml,其中包括了CustomEditorConfigurer的配置、具体实现在测试在main里面
5.bean的加载过程
主要分为两个阶段,容器启动阶段和实例化阶段。
- 容器启动阶段主要是加载Configuration MetaData。通过各种BeanDefinitionReader类来将xml文件映射BeanDefinition,里面包含了类的所有信息,但是不包括类的实例。容器启动最后可以附加一步BeanFactoryPostProcessor,可以将读完的BeanDefinition中的某一些信息进行修改,也就是上面第四点的内容,通常情况下,用于读取.yml中的配置信息,比如一个springboot的项目,启动的时候如果没有.yml就会加载默认的,如果有了的话就覆盖默认的值。
- 实例化阶段:下图为BeanFactory中的实例化过程。
- 实例化bean,实例化bean主要是根据BeanDefintion中的信息,结合CglibSubclassingInstantiationStrategy以及不同的bean定义类型,返回BeanWrapper类型,然后通过这个beanwrapper设置属性,类似于下面的代码。
BeanWrapper newsProvider = new BeanWrapperImpl(provider); newsProvider.setPropertyValue("newsListener", listener); newsProvider.setPropertyValue("newPersistener", persister);
- 容器检查Aware接口,同时对于依赖的对象进行实例化。实现Aware接口的类,可以将一些信息放到bean里面,例如:BeanNameAware就可以把类名放到这个bean里面、ApplicationContextAware可以把实现这个Bean的ApplicationContext引用放到里面。
- BeanPostProcessor会处理满足要求的实例化后的对象。两个方法前一个就是在Initialization之前执行,后一个在之后,前一个主要用于上一个所说的Aware实现类的修改,或者生成代理对象。如果需要自定义,我们只需要实现BeanPostProcessor类,override它的postProcessBeforeInitialization方法,然后对指定的类进行修改就好了,具体实现可以看PasswordDecodePostProcessor
public interface BeanPostProcessor {Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
- InitializingBean,在上一步结束后检测当前对象是否实现了InitializingBean,如果是就会调用对象的afterPropertiesSet方法,这个主要是用于一些初始化的操作,比如一个类,有init()方法或者初始化一些默认值的方法,就可以实现InitializingBean,并在里面调用init()方法。applicationcontext可以使用
init-method
在xml中配置初始化方法。 - DisposableBean,然后查看是否实现了DisposableBean,如果实现了,就会为该实例注册一个用于对象销毁的回调(callback),也就是在销毁之前先执行这个逻辑。applicationcontext可以使用
destroy-method
在xml中配置初始化方法。可以用于数据库关闭连接等。在getBean()中只是把这个类注册到disposableBeans中(一个map),如果要摧毁这个bean,还是需要在程序中((ConfigurableListableBeanFactory)container).destroySingletons();
6. AbstractApplicationContext和ResourceLoader之间的关系
AbstractApplicationContext自身继承了实现了DefaultResourceLoader和ResourcePatternResolver。具体继承实现关系如下图。
同时自身有一个PathMatchingResourcePatternResolver类型的变量,在初始化ResourcePatternResolver的时候因为自身继承了ResourceLoader,会将自身作为参数添加到ResourcePatternResolver中,所以当调用getResources的时候,其实就是调用一个以DefaultResourceLoader(AbstractApplicationContext继承这个)为参数的PathMatchingResourcePatternResolver的getResources方法。
7.Reource里面包含了什么,以及和recourceloader之间的关系
包含了这个文件的信息。包括文件名,file,inputStream,Description,URL。
recourceloader接口中有一个getResource,不同的实现类不同,也就是根据传进来的路径创建一个resource并返回。DefaultResourceLoader中并没有resource属性。
8. 基于注解方式的注入里面都做了什么
根据书中的思路来,首先,当我们给一个类加入@Autowire
之后,就可以自动绑定依赖,而这个依赖就需要在xml文件中声明<bean></bean>
,同时,容器需要去读取这个bean,就像之前的bean实例化的时候,在实例化bean,并且设置了对象之后,可以使用BeanPostProccessor来重新设置它的field,而spring提供了AutowiredAnnotationBeanPostProcessor实现,来作为读取Autowire的bean,那么我们只需要在xml中添加<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
即可。然后为了简化这两个东西的配置,我们可以通过<context:annotation-config/>
配置来同时把AutowiredAnnotationBeanPostProcessor 和CommonAnnotationBeanPostProcessor注册到容器,同时还会把PersistenceAnnotationBeanPostProcessor和RequiredAnnotationBeanPostProcessor一并进行注册。但是还是需要在这个xml里面配置最基础的<bean id="" class=""></bean>
,为了再次简化,我们可以在需要初始化的bean类上面添加@Component
加上之后设置扫描路径,扫描指定路径下面的包,如果带有这个@Component
就会提取该类的相关信息,构建对应的BeanDefinition,然后把构建完的BeanDefinition注册到容器。classpath-scanning功能的触发是由<context:component-scan>
决定的<context:component-scan base-package="..."/>
可以使用这种方式来设置路径,当然这个方法中也会注册各种BeanPostProcessor包。
AOP部分
1. 当ProxyFactory作为weaver的时候,为什么需要使用接口类作为代理对象?
IRequestable proxyObject=(IRequestable)weaver.getProxy();
SpringAop在使用代理模式实现代理对象的时候,一般采用动态代理和CGLIB,分别对实现某个接口的类和没有任何接口的目标类进行代理。如果一个类实现了某个接口,那么这个类就会默认采用动态代理的方式,所以返回的也是一个接口的实现类,因此就需要使用接口类作为代理对象,而没有实现任何类型的就会默认采用CGLIB的方式。
书中解释,在代理对象的场景中,接口的具体实现类和这个具体实现类的代理对象是两个不同的对象,我们可以将接口实现类和它的代理对象都强制转化为接口类型,而无法将代理对象类型强制转化为接口实现类类型。如动态代理示例
当然可以通过weaver.setProxyTargetClass(true)
将有实现某个接口的类通过CGLIB生成代理对象。
2. ProxyFactory内部的构造
ProxyFactory继承了ProxyCreatorSupport,提供getProxy()
方法,getProxy()
调用了ProxyCreatorSupport中的createAopProxy()
,ProxyCreatorSupport包含属性AopProxyFactory,这个属性是创建Proxy的工厂类,DefaultAopProxyFactory是它的实现,调用AopProxyFactory的createAopProxy方法后,最后根据目标类的类型获得JdkDynamicAopProxy(动态代理)或ObjenesisCglibAopProxy(CGLIB)
《Spring 揭秘》读书笔记相关推荐
- 读书笔记 | 墨菲定律
1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...
- 读书笔记 | 墨菲定律(一)
1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...
- 洛克菲勒的38封信pdf下载_《洛克菲勒写给孩子的38封信》读书笔记
<洛克菲勒写给孩子的38封信>读书笔记 洛克菲勒写给孩子的38封信 第1封信:起点不决定终点 人人生而平等,但这种平等是权利与法律意义上的平等,与经济和文化优势无关 第2封信:运气靠策划 ...
- 股神大家了解多少?深度剖析股神巴菲特
股神巴菲特是金融界里的传奇,大家是否都对股神巴菲特感兴趣呢?大家对股神了解多少?小编最近在QR社区发现了<阿尔法狗与巴菲特>,里面记载了许多股神巴菲特的人生经历,今天小编简单说一说关于股神 ...
- 2014巴菲特股东大会及巴菲特创业分享
沃伦·巴菲特,这位传奇人物.在美国,巴菲特被称为"先知".在中国,他更多的被喻为"股神",巴菲特在11岁时第一次购买股票以来,白手起家缔造了一个千亿规模的 ...
- 《成为沃伦·巴菲特》笔记与感想
本文首发于微信公众帐号: 一界码农(The_hard_the_luckier) 无需授权即可转载: 甚至无需保留以上版权声明-- 沃伦·巴菲特传记的纪录片 http://www.bilibili.co ...
- 读书笔记002:托尼.巴赞之快速阅读
读书笔记002:托尼.巴赞之快速阅读 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<快速阅读>之后,我们就可以可以快速提高阅读速度,保持并改善理解嗯嗯管理,通过增进了解眼睛和大脑功能 ...
- 读书笔记001:托尼.巴赞之开动大脑
读书笔记001:托尼.巴赞之开动大脑 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<开动大脑>之后,我们就可以对我们的大脑有更多的了解:大脑可以进行比我们预期多得多的工作:我们可以最 ...
- 读书笔记003:托尼.巴赞之思维导图
读书笔记003:托尼.巴赞之思维导图 托尼.巴赞的<思维导图>一书,详细的介绍了思维发展的新概念--放射性思维:如何利用思维导图实施你的放射性思维,实现你的创造性思维,从而给出一种深刻的智 ...
- 产品读书《滚雪球:巴菲特和他的财富人生》
作者简介 艾丽斯.施罗德,曾经担任世界知名投行摩根士丹利的董事总经理,因为撰写研究报告与巴菲特相识.业务上的往来使得施罗德有更多的机会与巴菲特亲密接触,她不仅是巴菲特别的忘年交,她也是第一个向巴菲特建 ...
最新文章
- vs中将网站aspx.cs文件打包成一个dll
- 二分法细节学习-mid
- Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_2
- 天玥运维安全网关默认密码_Soul网关发布全新架构V2.2.0,让高性能网关变得如此简单
- java plat停止_击按钮就停止运行,大牛帮我看看
- P2468 [SDOI2010]粟粟的书架 主席树 + 二分 + 二维前缀和
- python词云改颜色_一种用Python生成词云
- OSG仿真案例(5)——创建火光、爆炸(碎片)
- day3-python的基础类源码解析——collection类
- 如何使用python处理nc数据制作Mike风场文件--以ERA5数据为例
- 7-79 约分最简分式
- linux gz he xz,gz与xz两种压缩格式的对比
- 全网超火的情感文案号视频是怎么制作的?
- python (win32com) 批量删除 word (docx, doc) 中所有页眉、页脚 (Word.Application, Word.Basic)
- 匈牙利为庆贺第17届奥运会而发行的纪念邮票
- 【罗开传奇】传奇服务端调整人物属性脚本命令ChangeHumAbility
- 怎样防止苹果系统更新_苹果xs换过原装屏幕可以更新14系统吗?
- 汉诺塔(C语言实现)
- 美容院管理系统统一管理制度?
- 关于Cron表达式中的周一至周五正确的配置