深入理解spring

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解spring相关的知识,希望对你有一定的参考价值。

参考技术A 一 IOC容器概述

ioc类型:构造注入 属性注入 接口注入

类装载步骤:装载 验证  准备  解析  初始化 使用 卸载

classLoader:根加载器(bootstrap)  扩展加载器(ext)  系统加载器(app) 采用全盘负责委托机制

反射:可以从class对象获取构造函数 成员变量 方法三个主要反射类 

资源访问利器Resource:FileSystemResource  ClassPathResource ServletContextResource

BeanFactory ApplicationContext:beanFactory为ioc容器 spring框架的基础设施 面向spring,常用XmlBeanFactory ,applicationContext为应用上下文,面向开发者,主要实现类有classpathXmlApplicationContext  fileSystemXmlApplicationContext,区别:beanFactory 在第一次调用才初始化,而applicationContext是在容器启动初始化上下文即初始化bean

WebapplicationContext:两种初始化方法 org.springframework.web.context.ContextLoaderListener和org.springframework.web.context.ContextLoaderServlet

Bean生命周期:获取bean 初始化 设置属性 卸载

二 IOC中装配Bean

变量前两个字母要么全部大写,要么全部小写,eg:isBatch IDCard

依赖注入:属性注入、构造注入、工厂方法注入

Bean间关系:继承(parent),依赖(depends-on),引用(idref)

Bean的作用域:singleton prototype request session globalSession

基于注解启动spring容器:ApplicationContext ct = new AnnotationConfigApplicationContext(); ct.registe(Config.class); ct.refresh();

三 Spring高级

Bean创建过程:

    1.ResourceLoader 加载配置文件,生成对应的 Resource

    2.BeanDefinitionReader读取并解析resource,生成对应的 BeanDefinition ,并注册到BeanDefinitionRegister中,

    3.spring扫描BeanDefinitionRegister读取BeanDeifnition,如果bean实现工厂后处理器(BeanFactoryPostProcessor),对beanDefinition进行处理

    4.使用InstantiationStrategy初始化Bean,相当于new

    5.使用BeanWarpper对bean进行封装,完成bean属性设置工作

    6.利用容器中注册的bean后处理器(实现BeanPostProcessor接口),对bean进行后续加工

使用外部文件:使用<context:property-placeholder location=""/> 注file-encoding="utf8",使用$属性名引用属性值

加密外部文件:1.继承PropertyPlaceholderConfigurer 重写convertProperty(String propertyName,String propertyValue)方法,2.通过传统配置方式引入配置文件 <bean class="" p:location=""/>

国际化信息

本地化格式工具:DateFormat  NumberFormat  MessageFormat MessageSource

四 Spring Aop

基础知识:

    jdk动态代理:1.实现InvocationHandler 在invoke方法定义横切逻辑,通过反射调用目标类方法

                           2.通过Proxy.newProxyInstance() 为目标对象创建代理

    cglib动态代理:采用底层字节码技术,为类创建子类,在子类拦截所有调用父类方法的调用,性能优于jdk代理

                            1.实现MethodInteceptor 在inteceptor方法定义横切逻辑

                            2.通过字节码创建子类代理类

增强类型:前置 后置 异常 最终 环绕 引介,引介:为目标类创建新的方法或实现,类级别

五 基于@AspectJ和Schema的spring aop

注解:

通配符:* 匹配任意字符 只能匹配上下文的一个元素

                .. 匹配任意字符 匹配多个元素 

                + 表示类型匹配的所有类 包括子类

切点函数:@annotation(注解) 表示标识注解的所有方法

                    @execution(* com.baobaotao.Waiter+.*(..)) 表示匹配Waiter 及子类的所有方法,第一个*表示返回类型

                    args() 针对方法签名的 入参接受指定的类

                    @args() 入参接受指定注解

                    within() 同execetion()

                    target(M) 目标类匹配M

    @AspectJ进阶:命名切点,切点可以作为类似变量定义、引入

                            连接点对象,JoinPoint ProceedingJoinPoint(环绕增强) 

                            绑定连接点方法入参,通过args绑定

                            绑定代理对象,通过this

                            绑定类注解对象 通过within()或 target()

                            绑定返回值,通过returning

                            绑定抛出的异常,通过throwing

aop方式有四种:@AspectJ  <aop:aspect> Advisor <aop:advisor> 下面是对比

六 Spring对Dao的支持

DBCP数据源:BasicDataSource

    initialSize 默认0 初始化连接数  

    maxActive  8  最大活动链接

    maxIdle 8 最大空闲链接

    ValidationQuery sql查询语句 mysql:select 1  oracle : select 1 from dual

    testOnBorrow true  是否从池中取出链接前检查

    testWhileIdle  false  空闲链接是否被回收

    testBetweenEvictionRunsMillis -1  空闲链接回收期运行周期

    推荐testOnBorrow false,testWhileIdle true  testBetweenEvictionRunsMillis一个合适值

C3P0数据源:ComboPooledDataSource 

    acquireIncrement 链接用完时 c3p0一次性创建的数目

    initailPoolSize 初始化创建的数目 

    minPoolSize 连接池最小连接数  反之maxPoolSize 

    maxIdleTime 0 最大空闲时间,超时被丢弃 0为永不丢弃

七 Spring事务管理

事务特性:原子性 一致性 隔离性 持久性

读未提交:会脏读 不可重复读 幻读

读已提交(READ COMMITED):会不可重复读(两次读取同一记录 结果不一样) 幻读

可重复读(REPEATALBE READ):会幻读(一个事务 第一次读取到10条记录 第二次读取11条记录)

序列化(SERIALIABLE):读加共享锁 写加排它锁

ThreadLocal   原理:ThreadLocalMap  方法set(T t)  get()  remove()  initialValue()

事务传播行为:REQUIRED 如果没有事务则新建,有事务则加入                

                REQUIRES_NEW 新建事务 如果当前有事务则将其挂起

                SUPPORTS 支持当前事务,如果没事务则以无事务运行

                NOT_SUPPROTED 以非事务方式执行 如果当前有事务则挂起

                NEVER 以非事务运行 如果当前有事务 则抛出异常

                NESTED 如果没有事务,就新建事务,如果有,嵌套当前事务

使用XML配置声明式事务 

基于注解配置声明式事务

深入理解Spring注解机制:合并注解的合成

参考技术A 众所周知, spring 从 2.5 版本以后开始支持使用注解代替繁琐的 xml 配置,到了 springboot 更是全面拥抱了注解式配置。平时在使用的时候,点开一些常见的等注解,会发现往往在一个注解上总会出现一些其他的注解,比如 @Service :

大部分情况下,我们可以将 @Service 注解等同于 @Component 注解使用,则是因为 spring 基于其 JDK 对 元注解的机制 进行了扩展。

在 java 中,元注解是指可以注解在其他注解上的注解,spring 中通过对这个机制进行了扩展,实现了一些原生 JDK 不支持的功能,比如允许在注解中让两个属性互为别名,或者将一个带有元注解的子注解直接作为元注解看待,或者在这个基础上,通过 @AliasFor 或者同名策略让子注解的值覆盖元注解的值。

本文将基于 spring 源码 5.2.x 分支,解析 spring 如何实现这套功能的。

这是系列的第三篇文章,将详细介绍 Spring 是如何在经过搜索与属性映射后,将处理后的注解合成为合并注解的。

相关文章:

我们在前文了解用于搜索注解的合并注解聚合 MergedAnnotations 与用于完成注解属性映射的 AnnotationTypeMappings 和 AnnotationTypeMapping ,现在我们需要知道在 MergedAnnotations 这个容器中, AnnotationTypeMappings 和 AnnotationTypeMapping 是如何转为一个我们所需要的合并注解 MergedAnnotation 的。

与前文一样,我们以 AnnotatedElementUtils.findMergedAnnotations 方法作为入口:

我们在上文顺着 MergedAnnotations.get 一路找到 TypeMappedAnnotations.MergedAnnotationFinder 的 process 方法,在这里我们目睹了一个普通的注解的元注解被解析为 AnnotationTypeMappings 与 AnnotationTypeMapping 的过程:

该方法是 AnnotationTypeMapping 转为 MergedAnnotation 的关键。

TypeMappedAnnotation 是 MergedAnnotation 一个通用实现,在大部分情况下,我们所说的合并注解其实指的就是这个类。

通过它的构造方法我们得以了解其创建过程:

可以看得出, TypeMappedAnnotation 基本可以认为是 AnnotationTypeMapping 的包装类,它以一个 AnnotationTypeMapping 实例作为数据源,从而提供一些关于映射后的属性的相关功能。

回到 AnnotatedElementUtils.findMergedAnnotations ,我们可以看到,在通过 MergedAnnotations 获得了一个 MergedAnnotation 对象——实际上是 TypeMappedAnnotation 对象——之后,又调用了 MergedAnnotation.synthesize 方法,将 MergedAnnotation 转成了一个调用方指定类型的注解对象。

该方法先调用了 AbstractMergedAnnotation 的 synthesize 方法:

随后再调用了实现类 TypeMappedAnnotation 的 synthesize 方法:

继续点开 createSynthesized :

而 SynthesizedMergedAnnotationInvocationHandler 是一个用于 JDK 动态代理的 InvocationHandler ,我们不需要完全站看,仅需看看它的构造函数与 InvocationHandler.invoke 就能明白它的运作机制了:

至此,合并注解的合成机制已经很明确了:

承接上文,当我们使用 MergedAnnotation.synthesize 方法时,我们可能会得到两种对象:

而通过注解代理对象取值时,这些方法会被代理到 SynthesizedMergedAnnotationInvocationHandler 中存放的 MergedAnnotation 对象上,从而让这个代理对象通过原始注解的属性,获得与原始注解不一样的属性值。

当我们调用代理对象的属性值时,它会在 SynthesizedMergedAnnotationInvocationHandler 中,通过 invoke 代理到对应的方法上:

这里我们代理对象是如何获取注解属性值的:

这里的 MergedAnnotation.getValue 最终在经过多次跳转后,调到 TypeMappedAnnotation.getAttributeValue 上:

而这边的 getValue 方法就是真正要获取属性值的地方。

这一步有点复杂,主要是根据不同的情况,通过 AnnotationTypeMapping 中的几个属性映射数组,包括 aliasMappings 、 conventionMappings , annotationValueMappings 与 annotationValueSource 来确定最终用于取值的 AnnotationTypeMapping 对象与调用的方法在 AttributeMethods 中的下标:

至此,获取属性值的方法流程也走完了。

在这一章,我们了解了当通过 MergedAnnotations 获得注解并解析得到 AnnotationTypeMapping 后, AnnotationTypeMapping 是如何再转为我们所需的 MergedAnnotation ,以及在此之后, MergedAnnotation 又是如何生成我们最终所需要的代理注解的。

简而言之,当解析注解的元注解获得所需的 AnnotationTypeMapping 后, MergedAnnotation 会判断 AnnotationTypeMapping 是否发生过属性映射,如果没有则返回该映射对象对应的原始注解,否则就通过 SynthesizedMergedAnnotationInvocationHandler 生成一个对应类型的 JDK 动态代理对象。

当我们通过代理对象去调用注解的方法,获取注解的属性的时候, SynthesizedMergedAnnotationInvocationHandler 会把方法代理到对应的内部方法中,而获取属性时,还会通过 MergedAnnotation.getValue ,最终绕到 AnnotationTypeMapping 中获取被映射后的属性值。

以上是关于深入理解spring的主要内容,如果未能解决你的问题,请参考以下文章