框架

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文件

东瓜
18 声望3 粉丝

« 上一篇
并发编程
下一篇 »
分布式系统