WEB框架之Spring分析

一.Spring源码分析知识预备


1.1反射

  • 通过Class(obj.getClass/Class.forName)、
  • Constructor(clazz.newInstance默认是无参构造器/clazz.getConstructor(参数列表).newInstance)、
  • Method(clazz.getMethod('method名','method参数').invoke(obj,val))、
  • Field(clazz.getField获取子类父类的属性/clazz.getDeclaredField(name).set(obj,val)获取本类的属性/clazz.getSuperClass.getField)就可以使用反射进行一系列操作

1.2内省

  • 内省是Java语言对Bean类属性、事件的一种缺省处理方法。默认通过get/set方法进行属性注入(底层通过反射来进行调用),但是Java中提供了一套API用来访问某个属性的get/set方法,通过这些API可以使你不需要了解这个规则,这些API存放于包java.beans中。
  • BeanUtils.setProperty(obj, name, val) / Introspector.getBeanInfo(clazz)最终还是通过反射来实现的method.invoke(obj, val)

1.3动态代理

  • 实现InvocationHandler接口创建自己的调用处理器handler
  • 通过java.lang.reflect.Proxy的静态方法newProxyInstance创建代理类,以供调用

二.IOC


1.1IoC整体过程

  • Resource(xml、annotation、 class、 properties/yml) -> BeanDefinition ----> BeanWrapper----> bean 实例化

1.2FactoryBean和BeanFactory

  • BeanFactory用于管理bean,是所有容器最基本的形式,FactoryBean实际上是一个bean属于BeanFactory(API:getBean等)
  • ApplicationContext是BeanFactory的子接口,

ps:getBean根据名称找bean(返回object类型,返回requireType),根据类型找bean(返回该类型对象),根据名称和构造器的参数类型找bean。

  • FactoryBean用于创建对应bean的对象/实例(API:getObject等)

ps:注意&xxxFactoryBean是返回该工厂bean,而不是该工厂bean所创建出来的对象

1.3 AnnotationConfigApplicationContext

  • 初始化AnnotatedBeanDefinitionReader,#初始化类时注册APP主类的BeanDefinition
  • 初始化ClassPathBeanDefinitionScanner,#用来扫描指定路径下的注解并将BeanDefinition进行注册,需要调用scan方法手动添加路径才会使用

ps:如果是传参构造方法会进行注册#register,并且refresh刷新;如果不传参需要自己进行注册#register和刷新#refresh;

注册类的方式:~上下文的registry方法(无法参与BeanDefinition的设置);

~Import导入实现接口ImportBeanDefinitionRegistrar的类(可以参与BeanDefinition的设置);

~Import导入实现接口ImportSelector的类,方法返回需要注册类的数组;(无法参与BeanDefinition的设置)

~实现BeanDefinitionRegistryPostProcessor接口类的postProcessorBeanDefinitionRegistry回调方法来注册,另一个方法为空实现即可;(可以参与BeanDefinition的设置

~实现FactoryBean接口的getObject 和 getObjectType方法;(无法参与BeanDefinition的设置)

~使用@Compon直接 和 配置类中使用@Bean注解;(无法参与BeanDefinition的设置)

 

 

Import可导入的三种类:自定义的普通类,ImportSelector的实现类(用于指定需要注册为bean的Class名称),ImportBeanDefinitionRegistrar的实现类

1.4 refresh

  • 1.prepareRefresh(初始化环境变量的信息);
  • 2.obtainFreshBeanFactory,获取配置了上下文信息(初始配置的xml文件 或者 appconfig注解)的beanFactory;
  • 3.prepaerBeanFactory,设置属性,添加后置处理器,注册依赖组件信息;
  • 4.postProcessBeanFactory,执行BeanFactory的后置处理器;
  • 5.invokeBeanFactoryPostProcessors,执行已经在BeanFactory注册过的BD,进一步解析BD,先处理自己添加的(addBeanFactoryPostProcessor方法)实现BeanFactoryPostProcessor接口的类,在处理内置的实现该接口的类(比如spring内置的ConfigurationClassPostProcessor核心类--会解析APP主类)

 

  • 回调子接口(BeanDefinitionRegistryPostProcessor)的方法---------ConfigurationClassPostProcessor类------解析过程:先解析出PropertySource,ComponentScan,Import(会处理三种类),ImportResource(导入xml文件),Bean(方法),然后在进行加载注册解析出来的BD

@Import注解注册的方式:

~ImportSelector---先放入configurationClasses(包含importBeanDefinitionRegistrars)、

~Import普通类---等价ImportSelector、

~ImportBeanDefinitionRegistrar---先放入importBeanDefinitionRegistrars,在注册;

 

  • 回调父接口BeanFactoryPostProcessor的方法-------处理已经注册的BD,比如:ConfigurationClassPostProcessor实现类根据是否加上Configuration注解来判断是否对类进行cglib代理

如果加上@Configuration注解appconfig是一个full全注解类会进行cglib代理;如果不加则是一个lite半配置类返回原生对象(变为了人为控制实例化,单例可能会被实例化多次)

 

总结:调用自己添加的子接口方法,(First和Next实现了PriorityOrdered和Ordered)调用内置的子接口方法,(Finally)调用一次前面解析出的BD是否还需要调用子接口方法(比如:我自己定义的BeanDefinitionRegistryPostProcessor的实现类就还需要再次执行进行注册BD),调用自定义 以及 内置的父接口的方法。

然后同上,进行回调父接口的方法。

  • 6.registerBeanPostProcessors,注册BeanPostProcessor接口的实现类,注册被@AutoWired/@Required/@PostConstruct注解注入的BD;
  • 7.finishBeanFactoryInitialization,实例化非懒加载单例的bean并将对象缓存下来,构造器创建实例---属性注入---初始化之前的拦截器回调---初始化---初始化之后的拦截器回调,bean实例创建好再决定返回bean还是object

ps:AOP的原理,通过EnableAspectJAutoProxy注解导入AspectJAutoProxyRegistrar类,通过该类注册后置处理器BeanPostProcessor,然后在初始化之后的回调方法,获取通知 和 target类 进行生成代理类,而不是原生类;

 

Bean的生命周期过程:

  • bean的实例化,有参构造方法---无参构造方法---factoryMethod(需要xml进行配置),会先对所有的构造方法排序,按照访问权限 和 参数个数来排序,然后依次匹配,得到构造方法后会通过反射进行实例化;
  • bean创建好实例后,先注入属性(@Autowired,@Value注解等都会进行注入),然后执行初始化方法(接下来是自定义的init-method),并且加入初始化前后的拦截器 ;
  • bean初始化完成后,在getObjectForBeanInstance方法中需要根据name判断返回(bean的实例)FactoryBean,还是bean的实例(xxxFactoryBean)所创建出来的对象(xxx)
  • bean的使用完成之后进行销毁,执行销毁前的回调方法,执行销毁方法,接下来执行自定义的destroy-method;

 

bean的循环依赖问题:

  • 第一次getSingleton检查容器注册的缓存实例,第二次getSingleton会先创建FactoryBean在去获取对象(解决了循环依赖),就可以返回然后B就可以初始化成功,那么就等A进行初始化了,都成功后那么就整体创建成功了;
  • ~singletonFactories 三级缓存存放FactoryBean,在bean 构造器创建好实例并且初始化之前 缓存起来 ;
  • ~earlySingletonObjects 二级缓存存放 未经过初始化(属性注入 和 init)的对象;
  • ~singletonObjects 一级缓存存放 经过初始化(属性注入 和 init)的对象;

1.5 常用接口介绍

  • BeanPostProcessor:插手bean实例化过程,实例化之后,(初始化前后的回调方法)容器管理实例之前执行;应用场景AOP动态代理Bean;(每一个该接口的实现类都会对所有的Bean进行处理,相当于n*m的复杂度
  • InstantiationAwareBeanPostProcessor:BeanPostProcessor的子接口,可以在bean的实例化之后,populateBean属性注入时,进行回调(当自己需要实例化bean时使用);
  • InitializingBean:进行初始化Bean实例,方法afterPropertiesSet在属性注入之后进行执行;
  • BeanFactoryPostProcessor:用于已经注册了的BD 增加配置属性(比如:实现类ConfigurationClassPostProcessor的回调方法给 加了 @Configuration 的appconfig类加上cglib代理来管理bean 单例/多例);
  • BeanDefinitionRegistryPostProcessor:是BeanFactoryPostProcessor的子类,实现类ConfigurationClassPostProcessor的回调方法,先解析出注解的类,然后在实际进行注册BD
  • ImportSelector:回调方法返回一组类名,并自动把它变为BD不能自己操作BD;
  • ImportBeanDefinitionRegistrar:如果需要自己操作BD可以使用该接口的回调方法;
  • ImportAware:setImportMetadata回调方法 将注解的元信息进行设置;

三.AOP


3.1AOP介绍

  • 面向切面编程,通过动态代理来进行实现,只需要定义好增强方法 和 要被增强的方法,配置切点、通知和切面,然后就可以生成动态代理类来进行方法增强,避免了OOP面向对象编程的继承或者实现一个接口增加的代码之间的耦合性以及冗余代码量。

3.2概念

  • Aspect:切面,切入系统的一个切面 、
  • Join point:连接点,执行程序的一个点 、
  • Pointcut:切入点,用来匹配连接点 (包含很多个连接点)、确定在哪些连接点(Join point)处应用通知、
  • Advice:通知, 作用于连接点行为 、
  • Before advice : 前置通知 、
  • After returning advice : 后置通知 (异常不会执行)、
  • After throwing advice : 异常通知 、
  • After (finally) advice : 后置通知(不管是否发生异常) 、
  • Around advice : 环绕通知(等价于前置、后置以及异常通知,常用于事务管理)、
  • Advisor:通知器, 组合了通知(Advice)和具体哪些连接点(Join Point)/PointCut切入点(用正则匹配出具体的连接点)、一个InterceptionName对应一个Advicer、
  • Target Object:目标对象,被一个或者多个切面通知的对象 、
  • AOP proxy:AOP代理,JDK或者CGLIB

3.3AOP 实际过程

核心思想 : ,实例化之前调用,找到满足于目标对象(Pointcut)的所有Advice,并创建代理对象 , 最后进行调用.

  • 以@EnableAspectJAutoProxy注解为起点,里面存在@Import注解导入AspectJAutoProxyRegistrar类,该类实现了ImportBeanDefinitionRegistrar接口给spring容器注册BD;
  • 创建advisor BeanDefinition 
  • 1、找到容器中所有的Advisor
  • 2、过滤满足条件的Advisor
  • 3、创建代理对象,并把所有满足于目标对象的Advisor设置到其中。
  • 实际通过 JdkDynamicAopProxy / CglibAopProxy  来创建代理对象 、(需要传参,类加载器,接口,通知器=Advise + PointCut)  、
  • 最终,invoke方法进行调用拦截器(可以包含多个Advisor通知器)/直接调用;

四.MVC


4.1概念

  • view层自身为组合模式;
  • controller层与view为策略模式controller为算法的实现而view为策略的组合;
  • mode层和view为监听者模式model实现自身的回调方法在view中进行注册当view发生变化就会通知回调model进行处理;

拦截器和过滤器:都是通过AOP技术给方法进行增强,过滤器属于servlet里的,拦截器基于springMVC(更加常用);

4.2初始化

  • HttpServletBean实现了Servlet的init方法,
  • 紧接着调用了initServletBean,FrameworkServlet进行了实现,在通过initWebApplicationContext方法,
  • 进入到onRefresh方法,DispatcherServlet进行了实现,
  • 最终通过initStrategies方法对所有组件进行了初始化(包括HandlerMappings、HandlerAdapters)

ps:初始化加载的类是DispacterServlet通过静态代码块加载DispacterServlet.properties文件在通过反射来生成的。

4.3处理请求

  • DispacterServlet(前端控制器模式,请求统一进行分发处理)的doService方法,最终实现在doDispatch
  • 根据处理器映射器,从三种处理器中获取到对应的handler。(一种基于@Controller注解配置的就是注解的行的,一种实现Controller接口来实现也就是Bean的形式)
  • 通过处理器获取到对应的适配器(有四种),handlerAdapter。

ps:不同的处理器会匹配到不同的适配器,使用适配器模式解决了多处理器问题。

  • 适配器 通过反射来进行 实际的执行Controller里定义的逻辑,得到modelAndView
  • 将结果进行视图解析,然后进行视图渲染再返回给用户;

你可能感兴趣的:(Spring)