共计 7876 个字符,预计需要花费 20 分钟才能阅读完成。
框架
Spring
Spring 是一个容器框架,外部最外围的原理是 IOC 和 AOP
IOC:管制反转
是指将创建对象的控制权转移给 Spring 容器,并由 Spring 容器来治理对象与对象之间依赖关系,实现了对象与对象之间的关系的松耦合
外围:bean 工厂,形象工厂模式
形象工厂模式解析:
- Bean 工厂:提供了 bean 的创立性能,提供了对 bean 生命周期的治理,治理了 bean 与 bean 之间的依赖关系
- 整合其余框架,在配置文件中配置其余框架对象须要的参数就能够应用,不须要关怀其具体如何创立(如一些对象的创立须要先实例化其余对象)
- 本人编码时,能够更好的面向接口编程,因为接口的实现类交由 spring 注入,接口的调用者不须要关怀实现类的具体,后续实现类的逻辑批改时,接口调用者不须要改代码,或只须要改配置文件
AOP:面向切面编程
- 针对一些多个中央会用到的公共的行为和逻辑,抽取并封装为一个可重用的模块,并应用动静代理技术,应用反射创立指标类的代理类,在执行指标类办法的前后,可执行织入进去的切面逻辑
- 缩小零碎中的反复代码,进步了代码的可维护性
- 用于事务处理、日志记录、权限认证等
留神点:
Spring 是一个容器,但凡在容器里的对象才会有 Spring 所提供的这些服务和性能
Spring 对承受容器治理的全副的 bean,默认采纳单例模式治理
AOP 中的名词:
切面:
切点:
告诉:
Spring 蕴含哪些模块?
spring core:提供了框架的根本组成部分,包含管制反转(Inversion of Control,IOC)和依赖注入(Dependency Injection,DI)性能。
spring beans:提供了 BeanFactory,是工厂模式的一个经典实现,Spring 将治理对象称为 Bean。
spring context:构建于 core 封装包根底上的 context 封装包,提供了一种框架式的对象拜访办法。
spring jdbc:提供了一个 JDBC 的形象层,打消了繁缛的 JDBC 编码和数据库厂商特有的错误代码解析,用于简化 JDBC。
spring aop:提供了面向切面的编程实现,让你能够自定义拦截器、切点等。
spring Web:提供了针对 Web 开发的集成个性,例如文件上传,利用 servlet listeners 进行 ioc 容器初始化和针对 Web 的 ApplicationContext。
spring test:次要为测试提供反对的,反对应用 JUnit 或 TestNG 对 Spring 组件进行单元测试和集成测试。
动静代理
动静代理原理
动静代理不须要批改字节码,在运行时利用反射机制动静的为一个类的对象创立一个代理对象,代理对象能够在这个类的对象执行办法的前后插入一段代码逻辑,达到加强指标类办法的目标
代理类继承了 Proxy 类,实现了 InvocationHandler 接口
为什么 jdk 动静代理只能代理接口的办法:
- 因为动态创建的代理类实现了被代理类的接口,只具备接口中的办法
- 继承类曾经继承 Proxy 类,不能再继承代理类
- javaassit、cglib、asm 等批改字节码技术通过继承代理类实现,能够代理所有办法,被 final 润饰的除外
jdk 动静代理与 cglib 动静代理的区别
- jdk 动静代理实现了被代理类的接口,只能代理接口中的办法
- cglib 通过继承代理类实现,可代理所有办法,被 final 润饰的除外
- Spring 在创立代理类时,如果指标类有实现接口则应用 jdk 动静代理,否则应用 cglib
5、(摘要)一个典型的动静代理创建对象过程可分为以下四个步骤:1、通过实现 InvocationHandler 接口创立本人的调用处理器
IvocationHandler handler = new InvocationHandlerImpl(...);
2、通过为 Proxy 类指定 ClassLoader 对象和一组 interface 创立动静代理类
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});
3、通过反射机制获取动静代理类的构造函数,其参数类型是调用处理器接口类型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4、通过构造函数创立代理类实例,此时需将调用处理器对象作为参数被传入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
为了简化对象创立过程,Proxy 类中的 newInstance 办法封装了 2~4,只需两步即可实现代理对象的创立。生成的 ProxySubject 继承 Proxy 类实现 Subject 接口,实现的 Subject 的办法理论调用处理器的 invoke 办法,而 invoke 办法利用反射调用的是被代理对象的的办法(Object result=method.invoke(proxied,args))
IOC 容器的初始化过程
启动是通过 AbstractApplicationContext 的 refresh()办法进行启动,具体来说,这个启动包含 BeanDefinition 的 Resouce 定位、载入和注册三个根本过程。
1、第一个过程是 Resource 定位过程
指对 BeanDefinition 的资源定位过程。由对立的 ResourceLoader 实现。Bean 可能定义在 XML 中,或者是一个注解,或者是其余模式,这些都被用 Resource 来定位, 读取 Resource 获取 BeanDefinition
2、第二个过程是 BeanDefinition 的载入
这个载入过程是把用户定义好的 Bean 示意成 IoC 容器外部的数据结构,而这个容器外部的数据结构就是 BeanDefinition。
3、第三个过程是向 IoC 容器注册这些 BeanDefinition
这个过程把载入过程中解析失去的 BeanDefinition 向 IoC 容器进行注册。在 IoC 容器外部将 BeanDefinition 注入到一个 ConcurrentHashMap 中去。
这个 ConcurrentHashMap 是定义在 DefaultListableBeanFactory 中的 beanDefinitionMap
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
Spring 创立一个 Bean 的过程
1、实例化 Bean
上面 Spring Bean 的生命周期前 6 点
2、将 Bean 注册到 IOC 容器
DefaultSingletonBeanRegistry 中的 singletonObjects
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
Spring Bean 的生命周期
1、实例化 Bean
当客户向容器申请一个尚未初始化的 bean 时,或初始化 bean 的时候须要注入另一个尚未初始化的依赖时,BeanFactory 容器就会调用 getBean 办法尝试获取,如果 Bean 曾经被实例化则返回这个 Bean,如果没有实例化,则调用 createBean 办法,通过反射创立(BeanUtils 的 instantiateClass 办法)
2、设置对象属性
依赖注入,BeanWraper 实现,通过递归的形式获取指标 bean 及其所依赖的 bean
3、解决 Aware 接口
Spring 会检测该对象是否实现了 xxxAware 接口,并将相干的 xxxAware 实例注入给 Bean。
如果这个 Bean 曾经实现了 BeanNameAware 接口,会调用它实现的 setBeanName(String beanId)办法,此处传递的就是 Spring 配置文件中 Bean 的 id 值;
如果这个 Bean 曾经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory()办法,传递的是 Spring 工厂本身。
如果这个 Bean 曾经实现了 ApplicationContextAware 接口,会调用 setApplicationContext(applicationContext)办法,传入 Spring 上下文;
4、BeanPostProcessor 前置解决
BeanPostProcessor 是 Spring 提供的在 Bean 的初始化前后接管 IOC 容器回调的处理器,如果想对 Bean 进行一些自定义的解决,那么能够让 Bean 实现了 BeanPostProcessor 接口,那在 Bean 初始化前将会调用 postProcessBeforeInitialization 办法,在初始化后会调用 postProcessAfterInitialization 办法
5、InitializingBean 与 init-method
如果 Bean 实现了 InitializingBean 接口,将会执行重写的 afterPropertiesSet 办法
如果在 xml 中配置了 init-method,则会执行指定的初始化办法
6、BeanPostProcessor 后置解决
以上以上几个步骤实现后,Bean 就曾经被正确创立了
7、DisposableBean
当 Bean 不再须要时,会通过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用其实现的 destroy()办法;
8、destroy-method
最初,如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会主动调用其配置的销毁办法。
怎么在 Bean 初始化的先后执行一段代码逻辑
1、通过实现 InitializingBean/DisposableBean 接口来定制初始化之后 / 销毁之前的操作方法
2、通过在 xml 中配置 init-method/destroy-method 指定初始化之后 / 销毁之前调用的操作方法
3、在指定办法上加上 @PostConstruct 或 @PreDestroy 注解来制订该办法是在初始化之后还是销毁之前调用。
调用程序为:
Constructor > @PostConstruct > InitializingBean > init-method
Spring 反对的几种 bean 的作用域
(1)singleton:默认,每个容器中只有一个 bean 的实例,单例的模式由 BeanFactory 本身来保护。
(2)prototype:为每一个 bean 申请提供一个实例。
(3)request:为每一个网络申请创立一个实例,在申请实现当前,bean 会生效并被垃圾回收器回收。
(4)session:与 request 范畴相似,确保每个 session 中有一个 bean 的实例,在 session 过期后,bean 会随之生效。
(5)global-session:全局作用域,global-session 和 Portlet 利用相干。当你的利用部署在 Portlet 容器中工作时,它蕴含很多 portlet。如果你想要申明让所有的 portlet 共用全局的存储变量的话,那么这全局变量须要存储在 global-session 中。全局作用域与 Servlet 中的 session 作用域成果雷同。
循环依赖的解决办法
Spring 在利用构造方法创建对象实例,还未设置对象属性前,会将实例的援用放入 Spring 的三级缓存 singletonFactories 中,在设置对象属性时,会先查看三级缓存中是否曾经存在
DefaultSingletonBeanRegistry 类中的几个属性:
// 一级缓存,寄存曾经实例化实现的对象
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 三级缓存
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 二级缓存,通过三级缓存在获取对象会执行一些列的后置处理器,应用二级缓存晋升性能
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** Set of registered singletons, containing the bean names in registration order. */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
BeanFactory 和 ApplicationContext 有什么区别
- BeanFactory 是 Spring 最底层的容器接口,定义了 Bean 工厂的很多根底性能,如读取 bean 配置文档,治理 bean 的加载,治理 bean 的申明周期,保护 bean 之间的依赖关系。
- ApplicationContext 继承了 BeanFactory,并提供了一些扩大性能,如反对国际化、提供在监听器中注册 bean 事件等
- 利用场合咱们个别间接应用 ApplicationContext
怎么获取 ApplicationContext 与被 Spring 治理的 Bean
实现 ApplicationContextAware 接口,实现该接口的 setApplicationContext(ApplicationContext context)办法,并保留 ApplicationContext 对象。Spring 初始化时,会通过该办法将 ApplicationContext 对象注入。
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) {SpringContextUtil.applicationContext = applicationContext;}
}
获取到 ApplicationContext 后通过 applicationContext.getBean()办法获取 bean。
Spring 框架中都用到了哪些设计模式?
1、工厂模式:BeanFactory 就是简略工厂模式的体现,用来创建对象的实例;
2、单例模式:Bean 默认为单例模式。
3、代理模式:Spring 的 AOP 性能用到了 JDK 的动静代理和 CGLIB 字节码生成技术;
4、模板办法:比方 RestTemplate, JmsTemplate, JpaTemplate。用来解决代码反复的问题。
5、观察者模式:Spring 中 listener 的实现 –ApplicationListener
观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态产生扭转时,所有依赖于它的对象都会失去告诉被制动更新
6、责任链模式:SpringMVC 中的拦截器应用责任链模式实现
SpringMVC
执行流程
1、用户发送申请,前端控制器 DispatcherServlet 依据匹配规定接管到申请
2、DispatcherServlet 通过调用处理器映射器(HandlerMapping)、处理器适配器(HandlerAdapter)找到具体的处理器 Controller
3、处理器调用业务逻辑组件解决业务逻辑,实现后,将返回一个逻辑视图 ModelAndView 对象给 DispatcherSevlet
4、DispatcherSevlet 通过视图解析器 ViewResolver 将逻辑视图转化为真正的视图,并返回给客户端
拦截器与过滤器的区别
- 都是拦挡申请做一段逻辑解决
- 过滤器是 servlet 级别的,个别用来设置全局匹配的 url,设置编码格局等。拦截器是 spring 提供的组件和能力
- 拦截器能够获取 IOC 容器中的各个 bean,而过滤器就不行,这点很重要,在拦截器里注入一个 service,能够调用业务逻辑。
Mybatis
Mybatis 是一个对象关系映射框架,在配置文件中提供长久化类与数据库表的映射关系,框架在运行时参照映射文件中的信息,将对象长久化到数据库,或把从数据库查问进去的数据封装成对象。
次要有 Configuration、SqlSessionFactory、SqlSession、Executor、StatementHandler 等外围类
运行流程
1、程序启动时,Configuration 读取配置文件中的元数据,动静配置 mybatis 的属性,并创立 SqlSessionFactory 对象
2、SqlSessionFactory 对象中保留了以后数据库的配置信息和所有映射关系,保留了数据源的连接池
3、一条 sql 执行,会通过 SqlSessionFactory 创立一个会话对象 SqlSession,并绑定一个数据库连贯
4、SqlSession 会调用底下真正干活的执行器 Executor
5、Executor 负责 Sql 语句的动静生成,并调用手下的 StatementHandler 与 JDBC 的 statement 交互,并将获取到的数据由 jdbc 类型转换为 java 类型
Mybatis 的一级缓存与二级缓存
1、一级缓存作用域为 sqlSession,默认关上
2、二级缓存作用域为 Mapper,默认敞开
3、分布式系统开启 Mybatis 缓存容易产生脏数据,个别用 redis 等分布式缓存代替
4、当某个作用域执行 C /U/ D 操作后,缓存会被 clear
SpringBoot
SpringBoot 主动拆卸原理
1、SpringBoot 通过 main 办法启动调用 run()办法,run()办法会刷新容器,刷新容器时会去扫描 classpath 上面的包中的 META-INF/spring.factories 文件
2、这个文件中记录了很多主动配置类,在刷新容器时会将这些配置类加载到容器中,而后依据这些配置类中的 条件注解,来判断是否将这些配置类在容器中进行实例化
3、这些判断条件次要是判断我的项目是否有相干 jar 包,或是否引入相干 bean,这样 SpringBoot 就帮咱们实现了主动拆卸
@SpringBootApplication 是一个复合注解,这个注解中有一个 @EnableAutoConfiguration 注解,这个注解就是开启主动配置,这个注解会引入一个 AutoConfigurationImportSelector 类,去扫描 classpath 上面的包中的 META-INF/spring.factories 文件