Spring_源码解析_加载与初始化
Spring源码解析之BeanFactoryPostProcessor(一)

Spring源码解析之BeanFactoryPostProcessor(⼀)BeanFactoryPostProcessor在前⾯⼏个章节,笔者有介绍过BeanFactoryPostProcessor接⼝,在spring在解析BeanDefinition之后,根据BeanDefinition初始化bean之前,会回调我们编写的BeanFactoryPostProcessor实现类并调⽤postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)⽅法,spring会通过这个⽅法传⼊⼀个ConfigurableListableBeanFactory对象,我们可以对这个bean⼯⼚对象新增或修改BeanDefinition。
spring初始化bean⼀个典型的流程,就是根据我们标记在类上的@Component⽣成⼀个BeanDefinition,BeanDefinition中包含这个类的class对象,然后根据class对象⽣成实例。
如果我们编写两个Service:UserService和OrderService,并在类上标注@Component,再编写⼀个BeanFactoryPostProcessor接⼝,在接⼝中我们拿到UserService的BeanDefinition,并修改class为OrderService,那么我们从spring容器中获取userService这个bean,它的类型是UserService呢还是OrderService呢?来看下⾯的⽰例:package org.example.service;import ponent;@Componentpublic class OrderService {}package org.example.service;import ponent;@Componentpublic class UserService {}在Test1BeanFactoryPostProcessor类中,我们获取userService的BeanDefinition,并打印它的class对象,这⾥应该是UserService,然后我们再设置BeanDefinition的class为OrderServiceTest1BeanFactoryPostProcessor.javapackage org.example.service;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanFactoryPostProcessor;import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;import org.springframework.context.annotation.ScannedGenericBeanDefinition;import ponent;@Componentpublic class Test1BeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {ScannedGenericBeanDefinition beanDefinition = (ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("userService");System.out.println("UserService beanDefinition class:" + beanDefinition.getBeanClass());beanDefinition.setBeanClass(OrderService.class);}}MyConfig.javapackage org.example.config;import ponentScan;import org.springframework.context.annotation.Configuration;@Configuration@ComponentScan("org.example.service")public class MyConfig {}测试⽤例:@Testpublic void test01() {ApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class);System.out.println("userService class:" + ac.getBean("userService").getClass());}运⾏结果:UserService beanDefinition class:class erServiceuserService class:class org.example.service.OrderService可以看到,spring容器会回调我们编写的bean⼯⼚后置处理器BeanFactoryPostProcessor实现类Test1BeanFactoryPostProcessor ,在回调⽅法中,我们可以从bean⼯⼚获取spring容器已经解析的UserService对应的BeanDefinition对象,打印这个BeanDefinition对象的class对象也确实是UserService的class对象,之后我们修改UserService对应的BeanDefinition的class对象为OrderService的class对象,之后我们从spring容器获取beanName为userService的bean可以看到bean的实现类已经被替换成OrderService对象。
spring初始化方法的执行顺序及其原理分析

spring初始化⽅法的执⾏顺序及其原理分析⽬录Spring中初始化⽅法的执⾏顺序⾸先通过⼀个例⼦来看其顺序配置我们进⼊这个类看我们看到了annotation-config了我们重点看下这⾏代码我们直接看initializeBean这个⽅法spring加载顺序典例解决⽅案Spring中初始化⽅法的执⾏顺序⾸先通过⼀个例⼦来看其顺序/*** 调⽤顺序 init2(PostConstruct注解) --> afterPropertiesSet(InitializingBean接⼝) --> init3(init-method配置)*/public class Test implements InitializingBean {public void init3(){System.out.println("init3");}@PostConstructpublic void init2(){System.out.println("init2");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("afterPropertiesSet");}}配置<context:annotation-config/><bean class="com.cyy.spring.lifecycle.Test" id="test" init-method="init3"/>通过运⾏,我们得出其执⾏顺序为init2(PostConstruct注解) --> afterPropertiesSet(InitializingBean接⼝) --> init3(init-method配置)。
SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门

SpringMVC源码总结(⼀)HandlerMapping和HandlerAdapter⼊门刚接触SpringMVC,对它的xml⽂件配置⼀直⽐较模模糊糊,最近花了⼀点时间稍微看了下源代码,再加上调试,开始逐渐理解它,⽹上的类似的内容有很多,写本⽂主要是⾃⼰加深⼀下理解。
本⽂适合⽤过SpringMVC的开发者,⾔归正传,⾸先搭建⼀个最简单的⼯程体验⼀下。
该⼯程是基于maven的,pom配置不再说明,所使⽤的spring版本4.0.5。
⾸先是web.xml⽂件配置,最简单的配置Java代码1. <!DOCTYPE web-app PUBLIC2. "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"3. "/dtd/web-app_2_3.dtd" >4.5. <web-app>6. <display-name>Archetype Created Web Application</display-name>7. <servlet>8. <servlet-name>mvc</servlet-name>9. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>10. <load-on-startup>1</load-on-startup>11. </servlet>12.13. <servlet-mapping>14. <servlet-name>mvc</servlet-name>15. <url-pattern>/*</url-pattern>16. </servlet-mapping>17. </web-app>然后是mvc-servlet.xml⽂件的配置,上⾯配置DispatcherServlet会默认加载[servlet-name]-servlet.xml⽂件。
【Spring】依赖注入加载顺序

【Spring】依赖注⼊加载顺序⼀、Spring依赖注⼊depents-on参数depents-on是指指定Bean初始化及销毁时的顺序,使⽤depends-on属性指定的是Bean要先初始化完毕后才初始化当前Bean,由于只有Singleton Bean能被Spring管理销毁,所以当指定的Bean都是singleton时,使⽤depends-on属性指定的Bean要在指定的Bean之后销毁1、需要实体类以及配置⽂件测试实例⽇志信息1 package com.slp.spring.learn.helloworld.di;23 import java.io.File;4 import java.io.FileNotFoundException;5 import java.io.FileOutputStream;6 import java.io.IOException;7 /**8 * ResourceBean从配置⽂件中配置⽂件位置,然后定义初始化⽅法init中打开指定的⽂件,然后获取⽂件流;最后定义销毁⽅法destroy⽤于在应⽤程序关闭时调⽤该⽅法关闭掉⽂件流9 * @author sangliping10 *11 */12 public class ResourceBean {1314 private FileOutputStream fos;15 private File file;16 public void init(){17 System.out.println("ResourceBean:=============初始化");18 //加载资源,在此只是演⽰19 System.out.println("ResourceBean:==============加载资源,执⾏⼀些与操作");20 try {21 fos=new FileOutputStream(file);22 } catch (FileNotFoundException e) {23 // TODO Auto-generated catch block24 e.printStackTrace();25 }26 }2728 public void destory(){29 System.out.println("ResourceBean:============销毁");30 //释放资源31 System.out.println("ResourceBean:===========释放资源,执⾏⼀些清理操作");32 try {33 fos.close();34 } catch (IOException e) {35 // TODO Auto-generated catch block36 e.printStackTrace();37 }38 }3940 public FileOutputStream getFos() {41 return fos;42 }4344 public void setFos(FileOutputStream fos) {45 this.fos = fos;46 }4748 public File getFile() {49 return file;50 }5152 public void setFile(File file) {53 this.file = file;54 }5556 }package com.slp.spring.learn.helloworld.di;import java.io.IOException;/*** DependentBean中会注⼊ResourceBean,并从ResourceBean中获取⽂件流写⼊内容;定义初始化⽅法init⽤来定义⼀些初始化操作并向⽂件中输出⽂件头信息;最后定义销毁⽅法⽤于 * @author sangliping**/public class DependentBean {ResourceBean resourceBean;public void write(String ss) throws IOException {System.out.println("DependentBean:=======写资源");resourceBean.getFos().write(ss.getBytes());}// 初始化⽅法public void init() throws IOException {System.out.println("DependentBean:=======初始化");resourceBean.getFos().write("DependentBean:=======初始化=====".getBytes());}// 销毁⽅法public void destroy() throws IOException {System.out.println("DependentBean:=======销毁");// 在销毁之前需要往⽂件中写销毁内容resourceBean.getFos().write("DependentBean:=======销毁=====".getBytes());}public void setResourceBean(ResourceBean resourceBean) {this.resourceBean = resourceBean;}}<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance" xmlns:context="/schema/context"xsi:schemaLocation="/schema/beans /schema/beans/spring-beans-3.0.xsd/schema/context /schema/context/spring-context-3.0.xsd"><bean id="resourceBean" class="com.slp.spring.learn.helloworld.di.ResourceBean" init-method="init" destroy-method="destory"><property name="file" value="D://test.txt"></property><!-- Spring容器可以⾃动把字符串转换为java.io.File --></bean><bean id="dependentBean" class="com.slp.spring.learn.helloworld.di.DependentBean" init-method="init" destroy-method="destroy" depends-on="resourceBean"><property name="resourceBean" ref="resourceBean"></property></bean></beans>package com.slp.spring.learn.helloworld.di;import java.io.IOException;import org.junit.Test;import org.springframework.context.support.ClassPathXmlApplicationContext;/*2017-07-13 10:28:39,793 DEBUG main org.springframework.core.env.MutablePropertySources.addLast(MutablePropertySources.java:107) Adding [systemProperties] Proper 2017-07-13 10:28:39,884 DEBUG main org.springframework.core.env.MutablePropertySources.addLast(MutablePropertySources.java:107) Adding [systemEnvironment] Prope 2017-07-13 10:28:39,885 DEBUG main org.springframework.core.env.AbstractEnvironment.<init>(AbstractEnvironment.java:126) Initialized StandardEnvironment with Property 2017-07-13 10:28:39,918 INFO main org.springframework.context.support.AbstractApplicationContext.prepareRefresh(AbstractApplicationContext.java:510) Refreshing org.sp 2017-07-13 10:28:40,080 DEBUG main org.springframework.core.env.MutablePropertySources.addLast(MutablePropertySources.java:107) Adding [systemProperties] Property 2017-07-13 10:28:40,081 DEBUG main org.springframework.core.env.MutablePropertySources.addLast(MutablePropertySources.java:107) Adding [systemEnvironment] Prope 2017-07-13 10:28:40,086 DEBUG main org.springframework.core.env.AbstractEnvironment.<init>(AbstractEnvironment.java:126) Initialized StandardEnvironment with Property 2017-07-13 10:28:40,196 INFO main org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:315) Loading XML 2017-07-13 10:28:40,201 DEBUG main org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:72) Using JAXP provider 2017-07-13 10:28:40,382 DEBUG main org.springframework.beans.factory.xml.PluggableSchemaResolver.getSchemaMappings(PluggableSchemaResolver.java:140) Loading 2017-07-13 10:28:40,394 DEBUG main org.springframework.beans.factory.xml.PluggableSchemaResolver.getSchemaMappings(PluggableSchemaResolver.java:146) Loaded 2017-07-13 10:28:40,398 DEBUG main org.springframework.beans.factory.xml.PluggableSchemaResolver.resolveEntity(PluggableSchemaResolver.java:118) Found XML sch 2017-07-13 10:28:40,633 DEBUG main org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumen 2017-07-13 10:28:40,698 DEBUG main org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216 2017-07-13 10:28:40,700 DEBUG main org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:540) Bean f 2017-07-13 10:28:40,763 DEBUG main org.springframework.context.support.AbstractApplicationContext.initMessageSource(AbstractApplicationContext.java:807) Unable to lo 2017-07-13 10:28:40,817 DEBUG main org.springframework.context.support.AbstractApplicationContext.initApplicationEventMulticaster(AbstractApplicationContext.java:831) 2017-07-13 10:28:40,818 INFO main org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:603) P 2017-07-13 10:28:40,820 DEBUG main org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:215) Creati 2017-07-13 10:28:40,821 DEBUG main org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.ja 2017-07-13 10:28:40,844 DEBUG main org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactor 2017-07-13 10:28:40,936 DEBUG main org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableB ResourceBean:=============初始化ResourceBean:==============加载资源,执⾏⼀些与操作2017-07-13 10:28:40,966 DEBUG main org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.ja 2017-07-13 10:28:40,967 DEBUG main org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:246) Returning cached instance 2017-07-13 10:28:40,972 DEBUG main org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:215) Creati 2017-07-13 10:28:40,972 DEBUG main org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.ja 2017-07-13 10:28:40,974 DEBUG main org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactor 2017-07-13 10:28:40,977 DEBUG main org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:246) Returning cached instance 2017-07-13 10:28:40,980 DEBUG main org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableB DependentBean:=======初始化2017-07-13 10:28:40,982 DEBUG main org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.ja 2017-07-13 10:28:40,984 DEBUG main org.springframework.context.support.AbstractApplicationContext.initLifecycleProcessor(AbstractApplicationContext.java:858) Unable to 2017-07-13 10:28:40,985 DEBUG main org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:246) Returning cached instance 2017-07-13 10:28:40,995 DEBUG main org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:81) Searching for 2017-07-13 10:28:41,023 DEBUG main org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:81) Searching for 2017-07-13 10:28:41,028 DEBUG main org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:103) Could not fin 2017-07-13 10:28:41,066 DEBUG main org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:246) Returning cached instance DependentBean:=======写资源2017-07-13 10:28:41,114 INFO Thread-0 org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1042) Closing org.springf 2017-07-13 10:28:41,116 DEBUG Thread-0 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:246) Returning cached inst 2017-07-13 10:28:41,116 INFO Thread-0 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:444 2017-07-13 10:28:41,116 DEBUG Thread-0 org.springframework.beans.factory.support.DisposableBeanAdapter.invokeCustomDestroyMethod(DisposableBeanAdapter.java:30 DependentBean:=======销毁2017-07-13 10:28:41,117 DEBUG Thread-0 org.springframework.beans.factory.support.DisposableBeanAdapter.invokeCustomDestroyMethod(DisposableBeanAdapter.java:30 ResourceBean:============销毁ResourceBean:===========释放资源,执⾏⼀些清理操作*/public class MoreDependencyInjectTest {@Testpublic void testDependOn() throws IOException{ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("di/depent-on.xml");//注册销毁回调否则定义的销毁⽅法不执⾏context.registerShutdownHook();DependentBean dependent = context.getBean("dependentBean", DependentBean.class);dependent.write("测试写⼊数据");} }。
Spring源码分析基本介绍

Spring源码分析基本介绍摘要:本⽂结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。
若有描述错误之处,欢迎指正。
前⾔作为⼀名开发⼈员,阅读源码是⼀个很好的学习⽅式。
本⽂将结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码,若有描述错误之处,欢迎指正。
Spring是2003年兴起的⼀个轻量级Java开源框架,旨在解决企业应⽤开发的复杂性。
Spring发展⾄今,衍⽣出⾮常丰富的模块,并应⽤在多种场景,⽐如:桌⾯应⽤,Web应⽤等。
Spring的模块化可以允许你只使⽤需要的模块,⽽不必全部引⼊。
⽬录⼀、整体架构1. 核⼼容器2. 数据访问/集成3. Web4. AOP5. Test⼆、设计理念三、使⽤场景1. 典型的Spring web应⽤程序2. Spring中间层使⽤第三⽅web框架3. 远程调⽤4. EJBs-包装现存POJOs⼀、整体架构Spring框架是⼀个分层架构,他包含⼀系列的功能要素,并被分为⼤约20个模块,如下图所⽰(很遗憾,并没有找到Spring5的架构图,下图是Spring4的,但结合Spring5的源码来看,该图还是能够体现Spring5的核⼼模块)这些模块被总结为以下⼏部分。
1. 核⼼容器Core Container(核⼼容器)包含有Core、Beans、Context和Expression Language模块。
Core和Beans模块是框架的基础部分,提供IoC(控制反转)和DI(依赖注⼊)特性。
这⾥的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。
Core模块主要包含Spring框架基本的核⼼⼯具类,Spring的其他组件都要使⽤到这个包⾥的类,Core模块是其他组件的基本核⼼。
当然你也可以在⾃⼰的应⽤系统中使⽤这些⼯具类。
SpringBoot内置Tomcat启动原理源码分析

SpringBoot内置Tomcat启动原理源码分析1、获取SpringBoot内置Tomcat⾃动配置类: 在SpringBoot项⽬中引⼊spring-boot-starter-web依赖,就默认使⽤Tomcat容器,该依赖中引⼊spring-boot-starter-tomcat、spring-webmvc,就引⼊了tomtcat核⼼依赖和springMvc相关jar包,这样就间接地引⼊了tomcat。
在执⾏SpringBoot项⽬启动类的main()⽅法,启动SpringBoot项⽬的过程中会加载各个jar包下META-INF/spring.factories的⽂件,在该⽂件中包含着⾃动配置的⼦路径,在refresh()⽅法中的invokeBeanFactoryPostProcessors()中⾸先会对启动类上的 @SpringBootApplication 注解进⾏解析,最终调⽤ AutoConfigurationImportSelector类中的 getAutoConfigurationEntry() 加载 META-INF/spring.factories ⽂件中的⾃动配置类,得到⾃动配置类的全路径,其中 org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration 为tomcat⾃动配置类。
具体加载流程见:protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}AnnotationAttributes attributes = getAttributes(annotationMetadata);// 1、得到META-INF/spring.factories⽂件中配置的所有⾃动配置类List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);// 移除重复的配置类configurations = removeDuplicates(configurations);// 获取需要排除的⾃动配置类,eg:注解属性中的exculde的配置类Set<String> exclusions = getExclusions(annotationMetadata, attributes);// 检查需要被排除的配置类,因为有些不是⾃动配置类,需要抛异常checkExcludedClasses(configurations, exclusions);// 移除需要排除的配置类configurations.removeAll(exclusions);// 根据 META-INF/spring-autoconfigure-metadata.properties 中配置的规则过虑掉⼀部分配置类(根据@ConditionalOnXXX注解进⾏过滤)configurations = getConfigurationClassFilter().filter(configurations);// 获取符合条件的配置类后,触发 AutoConfigurationImportEvent 事件fireAutoConfigurationImportEvents(configurations, exclusions);// 将符合条件和需要排除的配置类封装进 AutoConfigurationEntry 对象中返回return new AutoConfigurationEntry(configurations, exclusions);}2、ServletWebServerFactoryAutoConfiguration - tomcat⾃动配置类分析3、创建tomcat⼯⼚@Configuration(proxyBeanMethods = false)@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)static class EmbeddedTomcat {@BeanTomcatServletWebServerFactory tomcatServletWebServerFactory(ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,ObjectProvider<TomcatContextCustomizer> contextCustomizers,ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {// 创建⽣产tomcat的⼯⼚TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();factory.getTomcatConnectorCustomizers().addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));factory.getTomcatContextCustomizers().addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));factory.getTomcatProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));return factory;}} 4、创建tomcat容器 在SpringBoot启动过程中会调⽤ AbstractApplicationContext.refresh() ⽅法,在该⽅法会调⽤onRefresh()⽅法,这个⽅法是个模板⽅法,最终会交给⼦类实现,在使⽤内置tomcat的SpringBoot项⽬中,最终会调⽤ ServletWebServerApplicationContext 实现(AbstractApplicationContext是GenericWebApplicationContext,ServletWebServerApplicationContext 是GenericWebApplicationContext),最终调⽤ServletWebServerApplicationContext 的createWebServer()⽅法创建 webServer。
图解SpringBoot解析yml全流程

图解SpringBoot解析yml全流程背景前⼏天的时候,项⽬⾥有⼀个需求,需要⼀个开关控制代码中是否执⾏⼀段逻辑,于是理所当然的在yml⽂件中配置了⼀个属性作为开关,再配合nacos就可以随时改变这个值达到我们的⽬的,yml⽂件中是这样写的:switch:turnOn: on程序中的代码也很简单,⼤致的逻辑就是下⾯这样,如果取到的开关字段是on的话,那么就执⾏if判断中的代码,否则就不执⾏:@Value("${switch.turnOn}")private String on;@GetMapping("testn")public void test(){if ("on".equals(on)){//TODO}}但是当代码实际跑起来,有意思的地⽅来了,我们发现判断中的代码⼀直不会被执⾏,直到debug⼀下,才发现这⾥的取到的值居然不是on⽽是true。
看到这,是不是感觉有点意思,⾸先盲猜是在解析yml的过程中把on作为⼀个特殊的值进⾏了处理,于是我⼲脆再多测试了⼏个例⼦,把yml 中的属性扩展到下⾯这些:switch:turnOn: onturnOff: offturnOn2: 'on'turnOff2: 'off'再执⾏⼀下代码,看⼀下映射后的值:可以看到,yml中没有带引号的on和off被转换成了true和false,带引号的则保持了原来的值不发⽣改变。
到这⾥,让我忍不住有点好奇,为什么会发⽣这种现象呢?于是强忍着困意翻了翻源码,硬磕了⼀下SpringBoot加载yml配置⽂件的过程,终于让我看出了点门道,下⾯我们⼀点⼀点细说!因为配置⽂件的加载会涉及到⼀些SpringBoot启动的相关知识,所以如果对这⼀块不是很熟悉的同学,可以先提前先看⼀下Hydra在古早时期写过⼀篇⽂章预热⼀下。
下⾯的介绍中,只会摘出⼀些对加载和解析配置⽂件⽐较重要的步骤进⾏分析,对其他⽆关部分进⾏了省略。
spring原理机制

spring原理机制转⾃:/nrain2/article/details/454593111,关于spring容器:spring容器是Spring的核⼼,该容器负责管理spring中的java组件,ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");//这种⽅式实例化容器,容器会⾃动预初始化所有Bean实例ctx.getBean("beanName");ApplicationContext 实例正是Spring容器。
ApplicationContext容器默认会实例化所有的singleton BeanSpring容器并不强制要求被管理组件是标准的javabean。
2,Spring的核⼼机制:依赖注⼊。
不管是依赖注⼊(Dependency Injection)还是控制反转(Inversion of Conctrol),其含义完全相同:当某个java实例(调⽤者)需要调⽤另⼀个java实例(被调⽤者)时,传统情况下,通过调⽤者来创建被调⽤者的实例,通常通过new来创建,⽽在依赖注⼊的模式下创建被调⽤者的⼯作不再由调⽤者来完成,因此称之为"控制反转";创建被调⽤者实例的⼯作通常由Spring来完成,然后注⼊调⽤者,所以也称之为"依赖注⼊"。
3,依赖注⼊⼀般有2中⽅式:设置注⼊:IoC容器使⽤属性的setter⽅式注⼊被依赖的实例。
<property name="" ref="">构造注⼊:IoC容器使⽤构造器来注⼊被依赖的实例。
<constructor-arg ref="">配置构造注⼊的时候<constructor-arg>可以配置index属性,⽤于指定该构造参数值作为第⼏个构造参数值。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Spring代码分析一:加载与初始化一般的Web项目都会在web.xml中加入Spring监听器,内容如下:<listener><listener-class>org.springframework.web.context.ContextLoaderList ener</listener-class></listener><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext-struts.xml,classpath :spring/applicationContext.xml</param-value></context-param>我们的问题是,Spring是何时以及如何加载我们的配置文件来初始化Bean工厂的,带着这些问题,我们展开研究:我们先来看看web.xml中配置的监听器的类,来回答我们的问题,Spring是何时来加载我们的配置文件的:org.springframework.web.context.ContextLoaderListener它继承了javax.servlet.ServletContextListener接口。
ServletContextListener是J2EE Servlet API中的一个标准接口,它能够监听ServletContext对象的生命周期,实际上就是监听Web应用的生命周期。
当Servlet容器启动或终止Web应用时,会触发ServletContextEvent事件,该事件由ServletContextListener来处理。
这里面有两个方法我们比较感兴趣:/*** Create the ContextLoader to use. Can be overridden in subclasses. * @return the new ContextLoader*/Protected ContextLoader createContextLoader() {Return new ContextLoader();}这个方法构造一个默认的ContextLoader,ContextLoader可以理解为Spring上下文的加载器。
之所以这样去定义这样一个类,是为了开发人员进行重写此方法来使用一个自定义的Spring 上下文的加载器。
/*** Initialize the root web application context.*/Public void contextInitialized(ServletContextEvent event) { this.contextLoader = createContextLoader();this.contextLoader.initWebApplicationContext(event.getServletCont ext());}这个方法很简单,仅仅只是调用了createContextLoader()构造了ContextLoader,并调用其初始化方法。
由此,我们可以得出结论,Spring是在Web项目启动时,通过ServletContextListener机制,来加载以及初始化Spring上下文的。
下面,我们好好研究一下Spring是如何加载其上下文的:我们先定位ContextLoader类。
看看此类的initWebApplicationContext()方法(省略了不重要的语句)/*** Initialize Spring's web application context for the given servlet context,* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and* "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.* @param servletContext current servlet context* @return the new WebApplicationContext* @throws IllegalStateException if there is already a root application context present* @throws BeansException if the context failed to initialize* @see #CONTEXT_CLASS_PARAM* @see #CONFIG_LOCATION_PARAM*/public WebApplicationContextinitWebApplicationContext(ServletContext servletContext)throws IllegalStateException, BeansException {if(servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APP LICATION_CONTEXT_ATTRIBUTE) !=null) {thrownew IllegalStateException("Cannot initialize context because there is already a root application context present - "+"check whether you have multiple ContextLoader* definitions in your web.xml!");}try{// Determine parent for root web application context, if any.ApplicationContext parent = loadParentContext(servletContext);// Store context in local instance variable, to guarantee that// it is available on ServletContext shutdown.this.context = createWebApplicationContext(servletContext, parent);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,this.context);currentContextPerThread.put(Thread.currentThread().getContextClas sLoader(),this.context);returnthis.context;}catch(RuntimeException ex) {logger.error("Context initialization failed", ex);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLIC ATION_CONTEXT_ATTRIBUTE, ex);throw ex;}catch(Error err) {logger.error("Context initialization failed", err);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLIC ATION_CONTEXT_ATTRIBUTE, err);throw err;}}其中的有两句比较重要,我们来看看:ApplicationContext parent = loadParentContext(servletContext);这个方法的用途主要是用来解决Spring共享环境的,即,如果我们有多个WAR包部署在同一个服务器上,而且这些WAR都共享某一套业务逻辑层。
如何共享一套业务逻辑包配置而不要每个W AR都单独配置,这时我们就可能需要Spring的共享环境了。
Protected ApplicationContext loadParentContext(ServletContext servletContext)throws BeansException {ApplicationContext parentContext =null;// 从web.xml中读取父工厂的配置文件,默认为:"classpath*:beanRefContext.xml"String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM);// 从web.xml中读取父类工厂的名称String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM);if(parentContextKey !=null) {// locatorFactorySelector may be null, indicating the default "classpath*:beanRefContext.xml"BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySele ctor);this.parentContextRef = eBeanFactory(parentContextKey);parentContext = (ApplicationContext)this.parentContextRef.getFactory();}return parentContext;}现在我们引入BeanFactoryLocator,它是Spring配置文件的一个定位器,Spring官方给它的定义是用来查找,使用和释放一个BeanFactory或其子类的接口。