spring源码分析

4 篇文章 0 订阅
4 篇文章 0 订阅

1、spring ioc源码分析

 

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

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

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

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> T getBean(String name, Class<T> requiredType) throws BeansException;
	<T> T getBean(Class<T> 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

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

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

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

1.3 源码分析IOC中的反射

AbstractRefreshableApplicationContext:

接下进入loadBeanDefinition的实现:

进入loadBeanDefinitions(..)。

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

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

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

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

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

进入bean的注册,

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

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

进入bean类型解析:

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

看看怎么创建的?

2 Spring获取bean对象

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

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实例化销毁之前执行。

@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方法");
    }
}
    <bean id="user" class="com.spring4.model.User" scope="prototype">
        <property name="name" value="xiaoming"/>
    </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里面配置<aop:aspectj-autoproxy/>  ,所以在配置文件中在遇到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

5 SpringMVC执行流程与源码分析

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

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

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

描述:

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。

  • 18
    点赞
  • 118
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
Spring 源码分析是一个相对复杂和庞大的话题,无法在一次对话中详细讨论。不过,我可以给你提供一些关于 Spring 源码分析的一般指导和建议。 1. 了解 Spring 的核心模块:Spring 框架是模块化的,每个模块都有不同的功能和职责。在开始源码分析之前,你需要先了解 Spring 的核心模块,如 Spring Core、Spring MVC、Spring Data 等。 2. 阅读官方文档和源码注释:Spring 框架的官方文档和源码注释是你学习和理解源码的重要资源。官方文档提供了对 Spring 各个模块的详细说明,源码注释则解释了代码的作用和实现细节。 3. 调试和跟踪代码:在进行源码分析时,调试器是你的好帮手。通过设置断点、单步跟踪以及观察变量的值,你可以深入理解代码的执行流程和逻辑。 4. 理解设计模式和原理:Spring 框架采用了许多设计模式和原理来实现其功能。在分析源码时,你需要熟悉这些设计模式和原理,例如依赖注入、AOP、工厂模式等。 5. 参考开源社区和博客:Spring 框架是一个非常活跃的开源社区,许多开发者在博客和论坛上分享了他们的源码分析和理解。阅读这些文章可以帮助你更好地理解 Spring 框架的实现细节。 请记住,深入分析 Spring 源码需要耐心和时间投入,同时也需要有一定的 Java 和设计模式的基础。希望这些指导对你有所帮助!如果你有具体的问题或者需要更详细的信息,欢迎继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值