1. spring是什么?
1)spring是一个生态,作为构建java应用的基础设施
2)通常说的spring指的是spring framework
3)spring是一个轻量级开源容器框架,解决对象间耦合问题
4)主要提供IOC和AOP功能
2. IOC
控制反转:将创建对象的权力由程序员转变为框架
spring提供两个系列的容器:beanfactory、applicationcontext
beanfactory是基础容器,提供简单实例化和获取对象
applicationcontext继承beanfactory,并新增一些功能
1)国际化支持 2)容器内消息机制 3)资源访问机制:扩展resourceloader、支持加载不同类型的resource
beanfactory采用延迟加载机制,getBean时候再创建,因此适合资源比较紧张的应用,applicationcontext在容器启动创建
IOC原理
以ClassPathXmlApplicationContext为例
2.1 创建beanfactory(obtainFreshBeanFactory)
2.1.1 new DefaultListableBeanFactory
2.1.2 加载beanBeanDefinition
如果是xml文件配置bean,则通过java dom解析,生成beanDefinition,并根据配置文件对其赋值
2.1.3 注册beanDefinition
1)注册beanDefinition,以beanName为key,beanDefinition为值
2)注册别名,以alias为key,beanName为值
最终两者将会注册到容器(DefaultListableBeanFactory)的beanDefinitionMap中
2.2 准备beanFactory(prepareBeanFactory)
设置一些基本的容器参数,包括:类加载器、EL表达式(${})解析器(填充属性)、注册基本的属性编辑器(读取设置属性)等
添加后置处理器ApplicationContextAwareProcessor到容器BPP链中
ps:ApplicationContextAwareProcessor在beforeInitialization中为ApplicationContextAware注入容器对象
2.3 postProcessBeanFactory
spring并没有具体实现,留给三方框架对容器准备完成后的定制化处理
2.4 invokeBeanFactoryPostProcessors
执行已经注册的beanFactoryPostProcessor以及其子BeanDefinitionRegistryPostProcessor,beanFactoryPostProcessor在初始化容器后的对外暴露点,允许在容器实例化bean前,读取bean定义并修改
ps:Mybatis的MapperScannerConfigurer就是一个BeanDefinitionRegistryPostProcessor,用于扫描basepackage下的mapper接口封装成beanDefinition并注册,因此mapper接口无需手动注册
2.5 registerBeanPostProcessors
注册BeanPostProcessors(后置处理器),将beanPostProcessors加到容器的一个list中
注册有优先级:实现PriorityOrdered>Ordered接口>大于普通处理器
2.6 initMessageSource
初始化messagesource国际化文件,如果用户定义则使用用户,否则使用默认发布者
2.7 initApplicationEventMulticaster
初始化消息发布者(applicationEventMulticaster),如果用户定义则使用用户,否则使用默认发布者
2.8 registerListeners
注册消费监听者到applicationEventMulticaster
2.9 finishBeanFactoryInitialization
完成剩余非懒加载的bean初始化
2.9.1 查找bean对象
遍历扫描到的beanNames集合,判断是否为factorybean(工厂bean),如果是则beanName加&,通过getBean初始化bean
三级缓存:
1)循环依赖:A依赖B,B依赖A
2)singletonObjects(一级)缓存完整bean、earlySingletonObjects(二级):提前暴露bean、singletonFactories:缓存bean工厂
3)缓存查找bean:如果一级没有则从二级获取,如果也没有,则从三级缓存中获得对象工厂(objectfactory)调用getObject,放入二级缓存同时删除三级缓存
4)解决循环依赖:A创建过程依赖B,将A半成品(提前暴露)放到三级缓存,然后去创建B,如果B也依赖A,则可以在三级缓存中获得A的半成品并继续初始化B
5)为何要三级缓存:涉及到AOP,如果Bean有代理,则注入的应该是代理类bean,但是没有代理类在初始化之后才创建,因此如果有循环依赖,则需要提前到objectfactory中创建
ps:三级缓存无法解决构造器注入循环依赖问题
2.9.2 创建bean对象
如果三级缓存中均无缓存,则需要创建
使用不同方法创建bean
1)工厂方法:如果配置factory-method,则调用对应的方法创建
2)如果含多个构造器,则通过参数确定调用对应构造方法
3)如果只有默认构造器,则通过反射调用构造器
2.6.3 属性注入
1)从beanDefinition获得需要注入的属性
2)通过byName(bean名)或者byType((bean类型)方式注入(反射调用set)
@Autowired:只byType @Resource:默认byName,也提供byType
2.6.4 初始化bean
1)调用aware接口方法
ps:aware(意识)、spring框架对bean是无侵入得分,bean无需感知容器,aware接口给框架内部使用,但是可以通过实现aware接口获得容器信息
beanNameAware:获得beanName
applicationContextAware:获得容器对象
2)执行beanPostProcessor
在bean实例化后(before)、初始化之前(after),允许对bean加工处理(aop就是利用bbp)
3)执行初始化方法
a. 实现initializingBean接口,调用afterPropertiesSet作为初始化方法
b. 配置init-method方法
单例和原型模式(多例)原理类似,只是单例创建好后将被缓存,而原型模式每次将会被创建
3. AOP
统一描述分散在对象、类、函数的横切关注点,将横切关注点与核心关注点分离
3.1 基本术语
1)joinpoint(连接点):可插入切面(横切逻辑)的点,如:方法执行前后、抛出异常前后
2)pointcut(切入点):需要进行切入的连接点
3)advice(通知):拦截后需要执行的逻辑
4)aspect(切面):aop实体概念,包含多个pointcut和advice。spring使用advisor描述,只含一个advice和pointcut
3.2 原理
可以使用织入器的方式也可以使用注解实现AOP
织入器:
proxyfactory:基本织入器,不和ioc结合
proxyfactorybean:和ioc容器结合
aspectproxyfactory:aspect与spring结合使用,更为方便
proxyfactorybean原理
1)配置:配置advisor(包括pointcut和advice),配置proxyfactorybean(设置代理接口、代理对象、拦截链advisor)
因为是factorybean,因此在getBean时,实际会调用getObjct
proxyfactorybeangetObject逻辑为:
2)初始化拦截器链
通过getBean初始化配置的拦截器并加到拦截器链中
3)生成代理对象
如果对象实现了接口,则使用jdk创建代理,否则使用cglib
jdk代理使用JdkDynamicAopProxy.getProxy,底层使用Proxy.newProxyInstance
newProxyInstance原理:
a. 首先查询缓存,看是否已经生成过代理
b. 使用ProxyGenerator.generateProxyClass生成字节码,通过类加载器加载class
c. 通过加载的class获得构造器,通过反射调用构造器完成初始化并返回
根据接口生成的代理类,调用接口实际就是执行传入hander的invoke方法
JdkDynamicAopProxy的invoke方法逻辑为:遍历配置的拦截器链,找出符合目标对象的拦截器,生成自己的拦截器链,然后逐步执行拦截器即可
使用cglib,spring通过CglibAopProxy.getProxy实现
getProxy直接创建一个enhancer,调用enhancer.create创建对象
创建对象的原理为:
a. 查找缓存
b.利用ASM技术生成代理字节码,反编译可知在代理对象中重写目标类的每个方法,在重写方法中调用interceptor(传入)的intercept方法
c.intercept和invoke类似,即遍历拦截器链,执行拦截
d. 使用FastClass调用目标对象方法
注解原理
1. @EnableAspectJAutoProxy:开启AOP功能,实际是向容器注入后置处理器bbp
2. bbp会拦截所有bean的初始化,如果bean需要增强,则生成代理对象返回
MVC
1. 初始化
1)tomcat启动时会去读取web.xml,创建servletcontext,这个context为整个应用共享,为spring ioc容器提供宿主环境
2)初始化IOC容器 如下方式
a. 配置ContextLoadListener以及springioc配置,在应用启动时调用contextInitialized将初始化容器并将其设置到servletcontext;同时配置DispatcherServlet,在其init方法中初始化mvc容器,并将其作为ioc容器的子容器
b. 只配置DispatcherServlet,则将spring和mvc的配置全部加载到一个容器
3)初始化mvc组件
包括:handlermap、multipartresolver、viewresolver、hanlderadapter等
2. 处理请求
请求到达tomcat,tomcat根据注册的servlet,调用service方法
service方法
1)getHandler
a. 遍历hanldermaps,找到合适的hanldermap
hanldermap一般来说有如下几种:simpleUrlhanldermap:使用配置的方式做url映射
requesthandlermap:使用注解方式
b. 通过url查找对应的handler
如果使用注解的方式,在实例化RequestMappingHandlerMapping时,会调用其afterPropertiesSet,在这个方法中会扫描加@controller或者@requestmapping注解的类,将其注册到容器。通过以url作为key,method作为vale,缓存到自身map,然后通过url查找对应的method
c. 将配置的拦截器放入执行链中,返回执行链
2)getHandlerAdapter
controller有多种实现方式,因此有多个适配器与之相适应,多种方式如:实现Controller接口,加@controller注解等
遍历handlerAdapter,调用其support方法,判断其是否支持此handler
3)执行处理逻辑
执行拦截器前置逻辑
handler.handle方法,掉用具体处理方法
后置逻辑
ps:实现HandlerInterceptor,配置拦截器
4) 视图渲染
controller处理完后返回modelAndView,ViewResolver根据处理结果获取对应的view,调用view的render接口,最终渲染到浏览器
如:BeanNameViewResolver就是根据mv中viewname,以其为beanname,找到对应bean,作为view进行处理
事务
1. 隔离级别
支持数据库的四种隔离级别+ISOLATION_DEFAULT(使用数据库默认隔离级别)
2. 传播行为(一个事务方法调用另一个事务方法)
required:有则加入,无则创建
supported:有则加入,无则忽略
mandatory:外部必须有,否则报错
requires_news:新建一个,如果外部有则报错
not_support:非事务运行,如果外部有则报错
....
3. 原理
声明式事务采用AOP环绕增强的方式实现,在目标方法之前开启事务,在目标方法之后提交或者回滚事务
开启事务:
1)设置autoCommit=false,关闭自动提交
2)将数据库连接connection绑定到本地变量,保证一个线程中多个操作使用同一连接进行
回滚事务:
1)如果是独立事务则直接回滚
2)如果事务有嵌套,则标记为回滚,待事务链执行完后统一回滚
3)回滚实际调用的conn.rollback
提交事务:
1)判断是否有回滚标记,如果没有则提交
2)如果是嵌套事务,则等待外部事务提交