spring源码分析

1、spring ioc源码分析

 

Spring IOC中bean的创建是利用反射+xml解析实现的,因此这里也围绕这个来做分析。

ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");

Spring所有的工作由这一句代码开始,接下就去剖析这个类ClassPathXmlApplicationContext。

spring源码分析_第1张图片

1.1 BeanFactory

由上图的继承关系可以看到,所有的类都包含这个接口(BeanFactory)。从下面的源码 可以看到BeanFactory定义了 IOC 容器的最基本形式,并提供了 IOC 容器应遵守的的最基本的接口,也就是Spring IOC 所遵守的最底层和最基本的编程规范。在  Spring 代码中, BeanFactory 只是个接口,并不是 IOC容器的具体实现,但是 Spring 容器给出了很多种实现,如 DefaultListableBeanFactory  XmlBeanFactory ApplicationContext 等,都是附加了某种功能的实现。

public interface BeanFactory {
	//这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,  
  //如果需要得到工厂本身,需要转义    
    //转义符“&”用来获取FactoryBean本身
	String FACTORY_BEAN_PREFIX = "&";
//根据bean的名字进行获取bean的实例,这是IOC最大的抽象方法
	Object getBean(String name) throws BeansException;
//根据bean的名字和Class类型进行获取Bean的实例,和上面方法不同的是,bean名字和Bean 的class类型不同时候会爆出异常
	 T getBean(String name, Class requiredType) throws BeansException;
	 T getBean(Class requiredType) throws BeansException;
	Object getBean(String name, Object... args) throws BeansException;
//检测这个IOC容器中是否含有这个Bean
boolean containsBean(String name);
//判断这个Bean是不是单利

	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//判断这个Bean是不是原型
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
//查询指定的bean的名字和Class类型是不是指定的Class类型
	boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException;
//这里对得到bean实例的Class类型
	Class getType(String name) throws NoSuchBeanDefinitionException;
//这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来 
	String[] getAliases(String name);
}

1.2 BeanDefinition

spring源码分析_第2张图片

从这个接口的函数名不难看出,这个接口是对应xml中bean的解析的。这里就不过多解释这些函数的意义了。

有一个类BeanDefinitionHolder,根据名称或者别名持有beanDefinition,它承载了beanNameBeanDefinition的映射信息。

spring源码分析_第3张图片

BeanWrapper:提供对Javabean的分析和操作方法,单个或者批量获取和设置属性值,获取属性描述符,查询属性的可读性和可写性等。支持属性的嵌套设置,深度没有限制。

1.3 源码分析IOC中的反射

AbstractRefreshableApplicationContext:

spring源码分析_第4张图片

接下进入loadBeanDefinition的实现:

spring源码分析_第5张图片

进入loadBeanDefinitions(..)。

spring源码分析_第6张图片

继续进入reader.loadBeanDefinitions(..)的实现:

spring源码分析_第7张图片

继续loadDefinitions的实现直到到达下面这个实现:

spring源码分析_第8张图片

这里直接进入解析单个bean的实现

spring源码分析_第9张图片

都是加载bean的定义的,此时选择xml形式的实现,直接找到如下实现:

spring源码分析_第10张图片

进入真正加载的这个方法。

spring源码分析_第11张图片

进入bean的注册,

spring源码分析_第12张图片

继续点击有关register这个单词的,直到下面这个类,很明显这个类就是遍历这个xml节点

spring源码分析_第13张图片

点击默认的,进入判断解析类型。

spring源码分析_第14张图片

进入bean类型解析:

spring源码分析_第15张图片

接下来,我们直接看他怎么解析的

spring源码分析_第16张图片

spring源码分析_第17张图片

看看怎么创建的?

spring源码分析_第18张图片

2 Spring获取bean对象

spring源码分析_第19张图片

spring源码分析_第20张图片

进入一看这个类,原来就是包含一些删除,添加(注册)等等的操作的类嘛,说白了就是维护一个hashMap,然后查询获取bean咯。

spring源码分析_第21张图片

3  bean生命周期

1、Spring对bean进行实例化(相当于new)

2、Spring将值和bean的引用注入到Bean对应的属性中

3、如果Bean实现了BeanNameAware接口,Spring将Bean的id传递给setBeanName()方法(实现BeanNameAware接口主要是为了通过Bean的引用来获得Bean的id,一般业务中是很少用到Bean的id的)

4、如果实现了BeanFactoryAware接口,Spring将调用setBeanFactory(BeanFactory bf)方法并把BeanFactory容器实例作为参数传入。(实现BeanFactoryAware主要目的是为了获取Spring容器,如bean通过Spring容器发布事件等)

5、如果Bean实现了ApplicationContextAware接口,Spring容器将调用setApplicationContext()方法,把Bean所在的应用上下文的引用传入。(作用和BeanFactory类似为获取Spring容器,不同的是Spring容器在调用setApplicationContext()时会把自己作为参数传入。而Spring容器在调用setBeanFactory前需要程序员自己指定(注入)BeanFactory里的参数)

6、如果Bean实现了BeanPostProcessor接口,Spring将调用他们的postProcessBeforeInitialization(预初始化)方法。(作用是在Bean实例化创建成功后对其进行增强处理,比如对bean进行修改,增加功能等)

7、如果bean实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet方法,作用与配置文件中对bean使用init-method声明初始化的作用一样,都是在bean的全部属性设置成功后执行的初始化方法。

8、如果bean实现了BeanPostProcess接口,Spring将调用他们的postProcessAfterInitialization方法(后初始化),在bean初始化之后执行。

9、此时bean应准备就绪,可以本程序使用,bean将一直驻留在应用上下文中给应用使用,直到应用上下文被销毁。

10、如果bean实现了DispostbleBean接口,Spring将调用他的destroy方法,作用与在配置文件中对bean调用destroy-method属性的作用一样,都是在bean实例化销毁之前执行。

spring源码分析_第22张图片

@Getter
public class User implements BeanNameAware,BeanFactoryAware,ApplicationContextAware,BeanPostProcessor,InitializingBean,DisposableBean {
    private String name;
    private Integer age;

    public void setName(String name) {
        System.out.println("2、填充属性");
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public User() {
        System.out.println("1、实例化");
    }


    @Override
    public void setBeanName(String s) {
        System.out.println("3、BeanNameAware的setBeanName:name="+s);
    }


    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("4、BeanFactoryAware的setBeanFactory。。");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("5、ApplicationContextAware的setApplication...");
    }

    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("6、bean初始化之前执行,beanname="+s);
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("8、bean初始化之后执行,beanname="+s);
        return o;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("7、属性设置成功后执行的初始化方法");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("9、销毁bean方法");
    }
}
    
        
    

Scope为原型,在容器初始化定义的bean创建之前,容器会自己去查找所有的beanPostProcessor进行创建,自定义的类,由于是实现了BeanPostProcessor接口,因此这时候会进行BeanPostProcessor的创建和注册,源码中,在注册BeanPostProcessor会进行getBean操作,即创建自定义的bean。由于默认的是单例模式,因此后面再次进行获取就不会再次调用postProcessBeforeInitialization()和postProcessAfterInitialization()方法,因为已经放入了spring缓存,直接获取,不需要实例,因此没有调用。如果你真的想使用的时候调用postProcessBeforeInitialization()和postProcessAfterInitialization()方法,将你的bean设置为原型模式(prototype),这样每次调用都会创建,因此初始化容器之后每次都会调用的。

4 AOP源码分析

AOP的好处:1、降低模块之间的耦合度2、更好的代码复用3、更容易扩展

流程说明

1)AOP标签的定义解析是从NamespaceHandlerSupport的实现类开始解析的,这个实现类就是AopNamespaceHandler。至于为什么会是从NamespaceHandlerSupport的实现类开始解析的,这个的话我想读者可以去在回去看看Spring自定义标签的解析流程,里面说的比较详细。

2)要启用AOP,我们一般会在Spring里面配置  ,所以在配置文件中在遇到aspectj-autoproxy标签的时候我们会采用AspectJAutoProxyBeanDefinitionParser解析器

3)进入AspectJAutoProxyBeanDefinitionParser解析器后,调用AspectJAutoProxyBeanDefinitionParser已覆盖BeanDefinitionParser的parser方法,然后parser方法把请求转交给了AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary去处理

4)进入AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法后,先调用AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,里面在转发调用给registerOrEscalateApcAsRequired,注册或者升级AnnotationAwareAspectJAutoProxyCreator类。对于AOP的实现,基本是靠AnnotationAwareAspectJAutoProxyCreator去完成的,它可以根据@point注解定义的切点来代理相匹配的bean。

5)AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法处理完成之后,接下来会调用useClassProxyingIfNecessary() 处理proxy-target-class以及expose-proxy属性。如果将proxy-target-class设置为true的话,那么会强制使用CGLIB代理,否则使用jdk动态代理,expose-proxy属性是为了解决有时候目标对象内部的自我调用无法实现切面增强。

6)最后的调用registerComponentIfNecessary 方法,注册组建并且通知便于监听器做进一步处理。

创建AOP代理流程

1、Spring容器启动,每个bean的实例化之前都会先经过AbstractAutoProxyCreator类的postProcessAfterInitialization这个方法,然后接下来是wrapIfNecessary

spring源码分析_第23张图片

spring源码分析_第24张图片

spring源码分析_第25张图片

spring源码分析_第26张图片

spring源码分析_第27张图片

5 SpringMVC执行流程与源码分析

SpringMVC其实底层也是封装HttpServlet实现的,我们知道HTTPServlet的流程是,每个请求到达,调用该Servlet的service方法。因此SpringMVC也是类似的呀,接下来走起。

1、所有的MVC请求都交给DispatcherServlet这个类处理,然后调用doService方法,交给doDispatch方法

spring源码分析_第28张图片

spring源码分析_第29张图片

最后通过视图解析器解析渲染后返回给客户端。

描述:

1、用户向服务器发送请求,请求被Spring前端控制Servlet DispatcherServlet捕获

2、DispatcherServlet对请求URL进行解析,得到请求资源标识符,然后根据URI调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回。

3、DispatcherServlet根据获得的Handler,选择一个合适的HandlerAdapter。

4、提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。

在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:

      HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息

      数据转换:对请求消息进行数据转换。如String转换成Integer、Double等

      数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等

      数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中

5、Handler执行完成后,向DispatcherServlet返回一个ModelAndView对象

6、根据返回的ModelAndView选择一个合适的ViewResolver返回给DispatcherServlet

7、ViewResolver结合Model和View,来渲染视图

8、将渲染结果返回给客户端

 

  为什么Spring只使用一个Servlet(DispatcherServlet)来处理所有请求?

用于集中统一化对外的请求接口,便于更好的封装内部逻辑。

Spring为什么要结合使用HandlerMapping以及HandlerAdapter来处理Handler?

    符合面向对象中的单一职责原则,代码架构清晰,便于维护,最重要的是代码可复用性高。如HandlerAdapter可能会被用于处理多种Handler。

你可能感兴趣的:(Java,spring,源码分析,MVC)