深入理解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的主要内容,如果未能解决你的问题,请参考以下文章

深入理解Spring Cloud一(3)Nacos配置中心

深入理解Spring Cloud一(4)Bean中的属性是如何刷新的?

深入理解Spring IoC

赠书:《深入理解 Spring Cloud 与实战》

深入理解Spring的ImportSelector接口

Spring AOP深入理解之拦截器调用