Spring源码分析

本文详细剖析了Spring的依赖注入实现、配置方式、初始化过程、SpringMVC源码解析及bean的生命周期。从构造器注入、setter注入到AOP原理,再到SpringMVC的web容器启动、DispatcherServlet初始化及JSP运行过程,最后讨论了bean的创建和销毁过程,旨在帮助开发者深化对Spring的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring源码分析

一、Spring依赖注入有三种实现方式:

1.构造器注入

2.Setter注入

3.FactoryBean接口注入

二、Spring三种配置方式:

1.XML

2.注解

3.Java的配置

三、Spring初始化过程:

1.初始化beanFactory,加载BeanDefinition的核心类和方法

2.初始化bean一个普通分支

3.Aop的实现原理

这个在getBean里面的AbstractAutowireCapableBeanFactory.initializeBean();里面发挥用处

img

JDK动态代理是需要被代理的类实现InvocationHandler接口,JDK动态代理只能对实现了接口的类生成代理,而不能针对类。

CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成final,对于final类或方法,是无法继承的。

四、SpringMvc源码解析

1.web容器启动的时候初始化web.xml里面的servlet,并且会调用servlet里面的init方法,当请求过来会匹配路径,如果路径匹配会调用servlet的service方法,这是javaee的规定

img

2.一般在web.xml里面配置DispatcherServlet,具体初始化流程:

HttpServletBean.init();HttpServletBean.initServletBean();FrameworkServlet.initServletBean();FrameworkServlet.initWebApplicationContext();FrameworkServlet.createWebApplicationContext();FrameworkServlet.configureAndRefreshWebApplicationContext();AbstractApplicationContext.refresh();//又跑到这里面来了FrameworkServlet.onRefresh();DispatcherServlet.onRefresh();DispatcherServlet.initStrategies();DispatcherServlet.initHandlerMappings();//请求响应流程GenericServlet.service();HttpServlet.service();FrameworkServlet.service();FrameworkServlet.processRequest();DispatcherServlet.doService();DispatcherServlet.doDispatch();//这里是处理逻辑mv = ha.handle(processedRequest, response, mappedHandler.getHandler());AnnotationMethodHandlerAdapter.handle();//这里通过req获得mathod,执行之后返回Object,将他转换成ModelAndView进入下一环节AnnotationMethodHandlerAdapter.invokeHandlerMethod();//这里是绘制viewDispatcherServlet.processDispatchResult();DispatcherServlet.render();DispatcherServlet.resolveViewName();//解析成view通过名字AbstractCachingViewResolver.createView();UrlBasedViewResolver.loadView();InternalResourceViewResolver.buildView();//UrlBasedViewResolver可以自己定义UrlBasedViewResolver.buildView();AbstractView.renderMergedOutputModel();InternalResourceView.renderMergedOutputModel();//渲染RequestDispatcher.forward();//跳转到jsp或者html

3.JSP运行过程

Tomcat源码下载地址 https://github.com/apache/tomcat

① 将JSP文件翻译成servlet源代码;

② 将servlet源代码编译成字节码文件;

③ 载入字节码并实例化和初始化;

① Tomat将http请求通过servlet转给JspServlet

② JspServlet在JspRuntimeContext的上下文中查找JspServletWrapper,如果没有找到就新建实例,找到了话就取出来用

③ JspServletWrapper初始化时也会初始化一个JspCompilationContext

④ JspServlet将请求转给JspServletWrapper的service方法进行处理

⑤ JspServletWrapper将判断系统是否允许重加载this.options.getDevelopment,如果允许将调用JspCompilationContext的编译方法compile

⑥ JspCompilationContext的compile方法通过判断jsp文件的时间戳来决定是否将类加载器JsperLoader的引用置null

⑦ JspServletWrapper通过getServlet方法从JspCompilationContext加载(load方法)jsp编译后的class类,并实例化

⑧ JspCompilationContext类在load时,首先要获得JsperLoader,如果它为null将新建一个实例,然后让JsperLoader这个类加载器加载jsp的class

⑨ JspServletWrapper获得实例化的servlet后,将把JspServlet转过来的请求交由这个servlet处理源码简要分析如下:

源码简要分析如下:

3.1、源码中涉及到的几个重要文件

JspServlet.java、JspServletWrap.java、JspRuntimeContext.java、Compiler.java、JDTCompiler.java(AntCompiler.java)

3.2、代码详细分析

JspServlet中涉及两重要方法:service方法和serviceJspFile,service方法主要用于获取请求JSP资源路径,serviceJspFile主要用于构建JspServletWrap。

JspRuntimeContext主要提供JspServletWrap的容器(用的是ConcurrentHashMap集合)。

Compiler主要用来翻译JSP文件和将其编译成字节码,具体的字节码产生实现由其子类实现(用到模版方法设计模式)。

JDTCompiler(AntCompiler)主要用来产生字节码文件。

JspServletWrap主要用来实例化Servlet并调用init进行初始化处理,并且调用servlet的service方法进行处理请求。

五、bean的生命周期

  1. Bean的建立, 由BeanFactory读取Bean定义文件,并生成各个实例
  2. Setter注入,执行Bean的属性依赖注入
  3. BeanNameAware的setBeanName(), 如果实现该接口,则执行其setBeanName方法
  4. BeanFactoryAware的setBeanFactory(),如果实现该接口,则执行其setBeanFactory方法
  5. BeanPostProcessor的processBeforeInitialization(),如果有关联的processor,则在Bean初始化之前都会执行这个实例的processBeforeInitialization()方法
  6. InitializingBean的afterPropertiesSet(),如果实现了该接口,则执行其afterPropertiesSet()方法
  7. Bean定义文件中定义init-method
  8. BeanPostProcessors的processAfterInitialization(),如果有关联的processor,则在Bean初始化之前都会执行这个实例的processAfterInitialization()方法
  9. DisposableBean的destroy(),在容器关闭时,如果Bean类实现了该接口,则执行它的destroy()方法
  10. Bean定义文件中定义destroy-method,在容器关闭时,可以在Bean定义文件中使用“destory-method”定义的方法

最后:

我想,可能还有很多人在今年刚过去的金三银四春招中保持着观望的形势,害怕自己的能力不够,或者是安于现状,觉得目前拿着几千的月薪觉得能够接受,那么你就要注意了,这是非常危险的!

我们身为技术人员,最怕的就是安于现状,一直在原地踏步,那么你可能在30岁就会迎来自己的职业危机,因为你工作这么久提升的只有自己的年龄,技术还是万年不变!

如果你想在未来能够自我突破,圆梦大厂,那或许以上这份Java学习资料,你需要阅读阅读,希望能够对你的职业发展有所帮助。

获取方式: 只需你**点赞+关注**后,进[Java架构资源交流群] ,找管理员获取哦-!

发展有所帮助。

获取方式: 只需你**点赞+关注**后,进[Java架构资源交流群] ,找管理员获取哦-!

在这里插入图片描述

代码解析2,部分摘抄 简单的说,在web容器中,通过ServletContext为Spring的IOC容器提供宿主环境,对应的建立起一个IOC容器的体系。其中,首先需要建立的是根上下文,这个上下文持有的对象可以有业务对象,数据存取对象,资源,事物管理器等各种中间层对象。在这个上下文的基础上,和web MVC相关还会有一个上下文来保存控制器之类的MVC对象,这样就构成了一个层次化的上下文结构。在web容器中启动Spring应用程序就是一个建立这个上下文体系的过程。Spring为web应用提供了上下文的扩展接口 WebApplicationContext: 如转载请注明,转载自:关注Java[http://www.gbsou.com] 本文链接: http://www.gbsou.com/2009/08/11/214.html - - Java代码 public interface WebApplicationContext extends ApplicationContext { //这里定义的常量用于在ServletContext中存取根上下文 String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT"; …… //对WebApplicationContext来说,需要得到Web容器的ServletContext ServletContext getServletContext(); } public interface WebApplicationContext extends ApplicationContext { //这里定义的常量用于在ServletContext中存取根上下文 String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT"; ...... //对WebApplicationContext来说,需要得到Web容器的ServletContext ServletContext getServletContext(); } 而一般的启动过程,Spring会使用一个默认的实现,XmlWebApplicationContext – 这个上下文实现作为在web容器中的根上下文容器被建立起来,具体的建立过程在下面我们会详细分析。 Java代码 public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext { /** 这是和web部署相关的位置信息,用来作为默认的根上下文bean定义信息的存放位置*/ public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"; public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"; public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml"; //我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh()的时候启动。 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { //对于XmlWebApplicationContext,当然使用的是XmlBeanDefinitionReader来对bean定义信息来进行解析 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) { } //使用XmlBeanDefinitionReader来读入bean定义信息 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { String[] configLocations = getConfigLocations(); if (configLocations != null) { for (int i = 0; i < configLocations.length; i++) { reader.loadBeanDefinitions(configLocations[i]); } } } //这里取得bean定义信息位置,默认的地方是/WEB-INF/applicationContext.xml protected String[] getDefaultConfigLocations() { if (getNamespace() != null) { return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX}; } else { return new String[] {DEFAULT_CONFIG_LOCATION}; } } } public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext { /** 这是和web部署相关的位置信息,用来作为默认的根上下文bean定义信息的存放位置*/ public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"; public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"; public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml"; //我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh()的时候启动。 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { //对于XmlWebApplicationContext,当然使用的是XmlBeanDefinitionReader来对bean定义信息来进行解析 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) { } //使用XmlBeanDefinitionReader来读入bean定义信息 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { String[] configLocations = getConfigLocations(); if (configLocations != null) { for (int i = 0; i < configLocations.length; i++) { reader.loadBeanDefinitions(configLocations[i]); } } } //这里取得bean定义信息位置,默认的地方是/WEB-INF/applicationContext.xml protected String[] getDefaultConfigLocations() { if (getNamespace() != null) { return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX}; } else { return new String[] {DEFAULT_CONFIG_LOCATION}; } } } 对于一个Spring激活的web应用程序,可以通过使用Spring代码声明式的指定在web应用程序启动时载入应用程序上下文(WebApplicationContext),Spring的ContextLoader是提供这样性能的类,我们可以使用 ContextLoaderServlet或者ContextLoaderListener的启动时载入的Servlet来实例化Spring IOC容器 – 为什么会有两个不同的类来装载它呢,这是因为它们的使用需要区别不同的Servlet容器支持的Serlvet版本。但不管是 ContextLoaderSevlet还是 ContextLoaderListener都使用ContextLoader来完成实际的WebApplicationContext的初始化工作。这个ContextLoder就像是Spring Web应用程序在Web容器中的加载器booter。当然这些Servlet的具体使用我们都要借助web容器中的部署描述符来进行相关的定义。 下面我们使用ContextLoaderListener作为载入器作一个详细的分析,这个Servlet的监听器是根上下文被载入的地方,也是整个 Spring web应用加载上下文的第一个地方;从加载过程我们可以看到,首先从Servlet事件中得到ServletContext,然后可以读到配置好的在web.xml的中的各个属性值,然后ContextLoder实例化WebApplicationContext并完成其载入和初始化作为根上下文。当这个根上下文被载入后,它被绑定到web应用程序的ServletContext上。任何需要访问该ApplicationContext的应用程序代码都可以从WebApplicationContextUtils类的静态方法来得到:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值