日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringBoot源码笔记分析

發(fā)布時(shí)間:2024/4/19 javascript 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot源码笔记分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

SpringBoot源碼筆記分析

1.基礎(chǔ)

1.配置SpringBoot熱部署

1.引入依賴

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId> </dependency>

2.配置IDEA

組合鍵 Ctrl+shift+alt+’/’ 彈出框

2.spring的配置文件

application.properties

application.yaml

2.1application.properties例子

server.port=8081 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.config.additional-location= spring.config.location= spring.config.name=application @Component //將類作為Bean注入到Spring容器中 @ConfigurationProperties(prefix = "person") //將配置文件以person開頭的屬性注入到該類中 public class Person {private int id; private String name; private List hobby; }

2.2 application.yaml配置文件

person:id: 1name: lucyhobby: [吃飯,睡覺]family: [father,mother]map: {k1: v1,k2: v2}pet: {type: dog,name: 旺財(cái)}

2.3.配置文件屬性注入

@Component public class Student {@Value("${person.id}")private int id;@Value("${person.name}")private String name; } // @Component @ConfigurationProperties(prefix = "person") public class Person {private int id; public void setId(int id) {this.id = id;} }

2.源碼刨析

2.1 依賴管理

1.為什么導(dǎo)入依賴時(shí)不需要指定版本
在spring-boot-starter-parent中的

<relativePath>../../spring-boot-dependencies</relativePath>

使用 dependencyManagement 進(jìn)行了版本管理

<dependencyManagement><dependencyManagement>

2.2 @SpringbootDemoApplication

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited //可以被子類繼承 @SpringBootConfiguration //該類為配置類 @EnableAutoConfiguration //啟動(dòng)配置功能 @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { }

2.2.1 @SpringBootConfiguration

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented@Configuration //配置類 public @interface SpringBootConfiguration {}

2.2.2 @EnableAutoConfiguration

@AutoConfigurationPackage //自動(dòng)配置包 @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { }

(1)@AutoConfigurationPackage

將(@SpringBootApplication)所在的包及其子包里面的所有組件掃描到Spring容器中

//spring框架的底層注解,它的作用就是給容器中導(dǎo)入某個(gè)組件類, @Import(AutoConfigurationPackages.Registrar.class) // 默認(rèn)將主配置類(@SpringBootApplication)所在的包及其子包里面的所有組件掃描到Spring容器中 public @interface AutoConfigurationPackage {} //==============Registrar方法========================static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {//取到了當(dāng)前application啟動(dòng)類所在的包名 com.youxiu.demoregister(registry, new PackageImport(metadata).getPackageName()); }}//============register============public static void register(BeanDefinitionRegistry registry, String... packageNames) {if (registry.containsBeanDefinition(BEAN)) {BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));}// 如果不存在該 BEAN ,則創(chuàng)建一個(gè) Bean ,并進(jìn)行注冊(cè)else {GenericBeanDefinition beanDefinition = new GenericBeanDefinition();beanDefinition.setBeanClass(BasePackages.class);beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);// 注冊(cè)beanDefinitionregistry.registerBeanDefinition(BEAN, beanDefinition);}}//============registerBeanDefinition============public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {Map var4 = this.beanDefinitionMap;synchronized(this.beanDefinitionMap) {//加入this.beanDefinitionMap.put(beanName, beanDefinition);List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);updatedDefinitions.addAll(this.beanDefinitionNames);updatedDefinitions.add(beanName);this.beanDefinitionNames = updatedDefinitions;this.removeManualSingletonName(beanName);}}

(2)@AutoConfigurationImportSelector.class

幫助SpringBoot容器將所有符合條件的額Configuation配置都加載到Ioc(ApplicationContext)中

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {//選擇導(dǎo)入public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}//加載 META-INF/spring-autoconfigure-metadata.properties 的配置文件//1. 加載配置文件META-INF/spring-autoconfigure-metadata.properties,從中獲取所有支持自動(dòng)配置類的條件//作用:SpringBoot使用一個(gè)Annotation的處理器來收集一些自動(dòng)裝配的條件,那么這些條件可以在META-INF/spring-autoconfigure-metadata.properties進(jìn)行配置。// SpringBoot會(huì)將收集好的@Configuration進(jìn)行一次過濾進(jìn)而剔除不滿足條件的配置類// 自動(dòng)配置的類全名.條件=值 下方第二張圖AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());} }

自動(dòng)配置的類全名.條件=值

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,AnnotationMetadata annotationMetadata) {// 1. 判斷是否開啟注解。如未開啟,返回空串if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}// 2. 獲得注解的屬性AnnotationAttributes attributes = getAttributes(annotationMetadata);// 3. getCandidateConfigurations()用來獲取默認(rèn)支持的自動(dòng)配置類名列表// spring Boot在啟動(dòng)的時(shí)候,使用內(nèi)部工具類SpringFactoriesLoader,查找classpath上所有jar包中的META-INF/spring.factories,// 找出其中key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的屬性定義的工廠類名稱,// 將這些值作為自動(dòng)配置類導(dǎo)入到容器中,自動(dòng)配置類就生效了List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);// 3.1 //去除重復(fù)的配置類,若我們自己寫的starter 可能存在重復(fù)的configurations = removeDuplicates(configurations);Set<String> exclusions = getExclusions(annotationMetadata, attributes);// 4.1 校驗(yàn)排除類(exclusions指定的類必須是自動(dòng)配置類,否則拋出異常)checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);// 5. 對(duì)所有候選的自動(dòng)配置類進(jìn)行篩選,根據(jù)項(xiàng)目pom.xml文件中加入的依賴文件篩選出最終符合當(dāng)前項(xiàng)目運(yùn)行環(huán)境對(duì)應(yīng)的自動(dòng)配置類//@ConditionalOnClass : 某個(gè)class位于類路徑上,才會(huì)實(shí)例化這個(gè)Bean。//@ConditionalOnMissingClass : classpath中不存在該類時(shí)起效//@ConditionalOnBean : DI容器中存在該類型Bean時(shí)起效//@ConditionalOnMissingBean : DI容器中不存在該類型Bean時(shí)起效//@ConditionalOnSingleCandidate : DI容器中該類型Bean只有一個(gè)或@Primary的只有一個(gè)時(shí)起效//@ConditionalOnExpression : SpEL表達(dá)式結(jié)果為true時(shí)//@ConditionalOnProperty : 參數(shù)設(shè)置或者值一致時(shí)起效//@ConditionalOnResource : 指定的文件存在時(shí)起效//@ConditionalOnJndi : 指定的JNDI存在時(shí)起效//@ConditionalOnJava : 指定的Java版本存在時(shí)起效//@ConditionalOnWebApplication : Web應(yīng)用環(huán)境下起效//@ConditionalOnNotWebApplication : 非Web應(yīng)用環(huán)境下起效//總結(jié)一下判斷是否要加載某個(gè)類的兩種方式://根據(jù)spring-autoconfigure-metadata.properties進(jìn)行判斷。//要判斷@Conditional是否滿足// 如@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })表示需要在類路徑中存在SqlSessionFactory.class、SqlSessionFactoryBean.class這兩個(gè)類才能完成自動(dòng)注冊(cè)。configurations = filter(configurations, autoConfigurationMetadata);// 6. 將自動(dòng)配置導(dǎo)入事件通知監(jiān)聽器//當(dāng)AutoConfigurationImportSelector過濾完成后會(huì)自動(dòng)加載類路徑下Jar包中META-INF/spring.factories文件中 AutoConfigurationImportListener的實(shí)現(xiàn)類,// 并觸發(fā)fireAutoConfigurationImportEvents事件。fireAutoConfigurationImportEvents(configurations, exclusions);// 7. 創(chuàng)建 AutoConfigurationEntry 對(duì)象return new AutoConfigurationEntry(configurations, exclusions);}

2.3. run方法

由SpringApplication對(duì)象與 Run兩部分組成

SpringApplication.run(DemoApplication.class, args);public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args); }

2.3.1 SpringApplication()

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;//斷言判空Assert.notNull(primarySources, "PrimarySources must not be null");//項(xiàng)目啟動(dòng)類 SpringbootDemoApplication.class設(shè)置為屬性存儲(chǔ)起來this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath();//設(shè)置初始器 //所謂的初始化器就是org.springframework.context.ApplicationContextInitializer的實(shí)現(xiàn)類,在Spring上下文被刷新之前進(jìn)行初始化的操作setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 設(shè)置監(jiān)聽器(Listener)setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 初始化 mainApplicationClass 屬性:用于推斷并設(shè)置項(xiàng)目main()方法啟動(dòng)的主程序啟動(dòng)類this.mainApplicationClass = deduceMainApplicationClass();}

2.3.1.1setInitializers初始化

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicates// 加載指定類型對(duì)應(yīng)的,在 `META-INF/spring.factories` 里的類名的數(shù)組Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));//創(chuàng)建spring工廠實(shí)例List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;}@SuppressWarnings("unchecked")private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,ClassLoader classLoader, Object[] args, Set<String> names) {List<T> instances = new ArrayList<>(names.size());for (String name : names) {try {Class<?> instanceClass = ClassUtils.forName(name, classLoader);Assert.isAssignable(type, instanceClass);// 獲得構(gòu)造方法Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);// 創(chuàng)建對(duì)象T instance = (T) BeanUtils.instantiateClass(constructor, args);// 加入到表instances.add(instance);}catch (Throwable ex) {throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);}}return instances;} // Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); //SpringFactoriesLoader.loadFactoryNames(type, classLoader) private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {MultiValueMap<String, String> result = cache.get(classLoader);if (result != null) {return result;}//1.獲取項(xiàng)目springFactory配置文件路徑 // jar:file:/D:/Java_code/apache-maven-3.5.2/resp/org/springframework/spring-beans/5.2.2.RELEASE/spring-beans-5.2.2.RELEASE.jar!/META-INF/spring.factories//jar:file:/D:/Java_code/apache-maven-3.5.2/resp/org/springframework/boot/spring-boot-devtools/2.2.2.RELEASE/spring-boot-devtools-2.2.2.RELEASE.jar!/META-INF/spring.factories//2.urls 轉(zhuǎn)換成 resource//3.遍歷resource key value封裝到了 MultiValueMap<String, String>try {Enumeration<URL> urls = (classLoader != null ?//加載META-INF/spring.factories//org.springframework.beans.BeanInfoFactory=org.springframework.beans.ExtendedBeanInfoFactoryclassLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));result = new LinkedMultiValueMap<>();while (urls.hasMoreElements()) {URL url = urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);for (Map.Entry<?, ?> entry : properties.entrySet()) {String factoryTypeName = ((String) entry.getKey()).trim();for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {result.add(factoryTypeName, factoryImplementationName.trim());}}}cache.put(classLoader, result);return result;}catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" +FACTORIES_RESOURCE_LOCATION + "]", ex);}}

2.3.2Run()

public ConfigurableApplicationContext run(String... args) {// 創(chuàng)建 StopWatch 對(duì)象,并啟動(dòng)。StopWatch 主要用于簡(jiǎn)單統(tǒng)計(jì) run 啟動(dòng)過程的時(shí)長(zhǎng)。StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;//異常管理Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();// (1)獲取并啟動(dòng)監(jiān)聽器SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {// 創(chuàng)建 ApplicationArguments 對(duì)象 初始化默認(rèn)應(yīng)用參數(shù)類// args是啟動(dòng)Spring應(yīng)用的命令行參數(shù),該參數(shù)可以在Spring應(yīng)用中被訪問。如:--server.port=9000ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//(2)項(xiàng)目運(yùn)行環(huán)境Environment的預(yù)配置ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);// 準(zhǔn)備Banner打印器 - 就是啟動(dòng)Spring Boot的時(shí)候打印在console上的ASCII藝術(shù)字體Banner printedBanner = printBanner(environment);// (3)創(chuàng)建Spring容器context = createApplicationContext();exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);// (4)Spring容器前置處理//這一步主要是在容器刷新之前的準(zhǔn)備動(dòng)作。包含一個(gè)非常關(guān)鍵的操作:將啟動(dòng)類注入容器,為后續(xù)開啟自動(dòng)化配置奠定基礎(chǔ)。prepareContext(context, environment, listeners, applicationArguments, printedBanner);// (5):刷新容器refreshContext(context);// (6):Spring容器后置處理afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}// (7)發(fā)出結(jié)束執(zhí)行的事件通知listeners.started(context);// (8):執(zhí)行RunnerscallRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;}

1.createApplicationContext

protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {switch (this.webApplicationType) {// 該類型為SERVLET類型,所以會(huì)通過反射裝載對(duì)應(yīng)的字節(jié)碼,case SERVLET:contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);break;case REACTIVE:contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);break;default:contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);}}catch (ClassNotFoundException ex) {throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);}}// 創(chuàng)建 ApplicationContext 對(duì)象return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);}

2.prepareContext

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {//設(shè)置容器環(huán)境,包括各種變量context.setEnvironment(environment);//設(shè)置上下文的 bean 生成器和資源加載器postProcessApplicationContext(context);//執(zhí)行容器中的ApplicationContextInitializerapplyInitializers(context);listeners.contextPrepared(context);if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beans//注冊(cè)啟動(dòng)參數(shù)bean,這里將容器指定的參數(shù)封裝成bean,注入容器ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}// Load the sourcesSet<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));listeners.contextLoaded(context);}

3.refreshContext

protected void refresh(ApplicationContext applicationContext) {// 斷言,判斷 applicationContext 是 AbstractApplicationContext 的子類Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);// 啟動(dòng)(刷新) AbstractApplicationContext((AbstractApplicationContext) applicationContext).refresh();}

3.自定義Starter

SpringBoot starter機(jī)制
SpringBoot 是由眾多starter組成(一系列的自動(dòng)化配置的start插件)
starter是SpringBoot中重要的一部分,理解為可插拔的插件

1.框架段

1.導(dǎo)入依賴

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId><version>2.2.2.RELEASE</version></dependency> </dependencies>

2.自定義一個(gè)Bean

@EnableConfigurationProperties(SimpleBean.class) @ConfigurationProperties(prefix = "simplebean") public class SimpleBean {private int id;private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "SimpleBean{" +"id=" + id +", name='" + name + '\'' +'}';} }

3.自定義自動(dòng)配置接口

//@ConditionalOnClass : 某個(gè)class位于類路徑上,才會(huì)實(shí)例化這個(gè)Bean。//@ConditionalOnMissingClass : classpath中不存在該類時(shí)起效//@ConditionalOnBean : DI容器中存在該類型Bean時(shí)起效//@ConditionalOnMissingBean : DI容器中不存在該類型Bean時(shí)起效//@ConditionalOnSingleCandidate : DI容器中該類型Bean只有一個(gè)或@Primary的只有一個(gè)時(shí)起效//@ConditionalOnExpression : SpEL表達(dá)式結(jié)果為true時(shí)//@ConditionalOnProperty : 參數(shù)設(shè)置或者值一致時(shí)起效//@ConditionalOnResource : 指定的文件存在時(shí)起效//@ConditionalOnJndi : 指定的JNDI存在時(shí)起效//@ConditionalOnJava : 指定的Java版本存在時(shí)起效//@ConditionalOnWebApplication : Web應(yīng)用環(huán)境下起效//@ConditionalOnNotWebApplication : 非Web應(yīng)用環(huán)境下起效 @Configuration @ConditionalOnClass public class MyAutoConfiguration {static {System.out.println("MyAutoConfiguration init....");}@Beanpublic SimpleBean simpleBean() {return new SimpleBean();}}

4.配置接口路徑

在resources目錄下新建 \META-INF\spring.factories

// 自動(dòng)配置的類全名.條件=值 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.youxiu.config.MyAutoConfiguration

2.使用端

@RunWith(SpringRunner.class) //測(cè)試啟動(dòng)器,并加載spring boot測(cè)試注解 @SpringBootTest class DemoApplicationTests {@Autowiredprivate SimpleBean simpleBean;@Testpublic void test(){System.out.println(simpleBean);} }

4.國際化配置

實(shí)現(xiàn)了 LocaleResolver 接口,重寫 resolveLocale()方法。覆蓋掉spring組件的LocaleResolver

@Configuration public class MyLocaleResovle implements LocaleResolver {// 自定義 區(qū)域解析方式@Overridepublic Locale resolveLocale(HttpServletRequest httpServletRequest) {// 獲取頁面手動(dòng)傳遞的語言參數(shù)值l : zh_CN en_US ''String l = httpServletRequest.getParameter("l");Locale locale = null;if(!StringUtils.isEmpty(l)){// 如果參數(shù)不為空,就根據(jù)參數(shù)值進(jìn)行手動(dòng)語言切換String[] s = l.split("_");locale = new Locale(s[0],s[1]);}else {//Accept-Language: zh-CN ,zh;q=0.9String header = httpServletRequest.getHeader("Accept-Language");String[] split = header.split(",");String[] split1 = split[0].split("-");locale = new Locale(split1[0],split1[1]);}return locale;}@Overridepublic void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {}// 將自定義的MyLocaleResovle重新注冊(cè)成一個(gè)類型為L(zhǎng)ocaleResolver的bean組件@Beanpublic LocaleResolver localeResolver(){return new MyLocaleResovle();} } <a class="btn btn-sm" th:href="@{/toLoginPage(l='zh_CN')}">中文</a><a class="btn btn-sm" th:href="@{/toLoginPage(l='en_US')}">English</a> login.tip=please sign in login.username=username login.password=password login.rememberme=remember me login.button=login

5.springBoot的默認(rèn)緩存

5.1代碼

@EnableCaching 全局注解

@EnableCaching // 開啟緩存 @SpringBootApplication public class Springboot04CacheApplication {public static void main(String[] args) {SpringApplication.run(Springboot04CacheApplication.class, args);} }

給方法添加

//@Cacheable: 將該方法查詢結(jié)果comment存放在springboot默認(rèn)緩存中//cacheNames: 起一個(gè)緩存命名空間 對(duì)應(yīng)緩存唯一標(biāo)識(shí)// value: 緩存結(jié)果 key:默認(rèn)在只有一個(gè)參數(shù)的情況下,key值默認(rèn)就是方法參數(shù)值 如果沒有參數(shù)或者多個(gè)參數(shù)的情況:simpleKeyGenerate// 查詢方法 //指定在 unless 指定在符合某個(gè)情況下不進(jìn)行緩存@Cacheable(cacheNames = "comment",unless = "#result==null")public Comment findCommentById(Integer id){Optional<Comment> byId = commentRepository.findById(id);if(byId.isPresent()){Comment comment = byId.get();return comment;}return null;}

5.2源碼分析

SprignBoot默認(rèn)裝配的是SimpleCacheConfiguration .使用CacheManager是ConcurrentMapCacheManager,底層是 ConcurrentMap

@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Cacheable {@AliasFor("cacheNames") //指定緩存的名稱 二選一String[] value() default {}; //指定緩存的名稱二選一@AliasFor("value")String[] cacheNames() default {}; //緩存數(shù)據(jù)的keyString key() default ""; //指定緩存數(shù)據(jù)的key的生成器String keyGenerator() default ""; //緩存管理器String cacheManager() default ""; //指定緩存解析器String cacheResolver() default ""; //指定在符合某條件下,進(jìn)行數(shù)據(jù)緩存String condition() default ""; //符合條件下,不進(jìn)行數(shù)據(jù)緩存String unless() default ""; // sync 是否使用異步緩存,默認(rèn)falseboolean sync() default false; } public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderAware {private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap(16);}

5.3redis緩存

配置文件

#Redis服務(wù)連接配置 #Redis服務(wù)地址 spring.redis.host=127.0.0.1 #Redis服務(wù)器連接端口 spring.redis.port=6379 #Redis服務(wù)器連接密碼 spring.redis.password=# 對(duì)基于注解的Redis緩存數(shù)據(jù)統(tǒng)一設(shè)置有效期為1分鐘,單位毫秒 spring.cache.redis.time-to-live=60000 @Autowiredprivate RedisTemplate redisTemplate; // 使用API方式進(jìn)行緩存:先去緩存中查找,緩存中有,直接返回,沒有,查詢數(shù)據(jù)庫public Comment findCommentById(Integer id){Object o = redisTemplate.opsForValue().get("comment_" + id);if(o!=null){//查詢到了數(shù)據(jù),直接返回return (Comment) o;}else {//緩存中沒有,從數(shù)據(jù)庫查詢Optional<Comment> byId = commentRepository.findById(id);if(byId.isPresent()){Comment comment = byId.get();//將查詢結(jié)果存到緩存中,同時(shí)還可以設(shè)置有效期為1天redisTemplate.opsForValue().set("comment_" + id,comment,1, TimeUnit.DAYS);return comment;}}return null;}

5.3自定義redis緩存序列化

package com.lagou.config;@Configuration public class RedisConfig {// 自定義一個(gè)RedisTemplate//基于 自定義一個(gè)RedisTemplate形式@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<Object, Object> template = new RedisTemplate<>();template.setConnectionFactory(redisConnectionFactory);// 創(chuàng)建JSON格式序列化對(duì)象,對(duì)緩存數(shù)據(jù)的key和value進(jìn)行轉(zhuǎn)換Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);// 解決查詢緩存轉(zhuǎn)換異常的問題ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);//設(shè)置redisTemplate模板API的序列化方式為jsontemplate.setDefaultSerializer(jackson2JsonRedisSerializer);return template;}//基于注解形式@Beanpublic RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {// 分別創(chuàng)建String和JSON格式序列化對(duì)象,對(duì)緩存數(shù)據(jù)key和value進(jìn)行轉(zhuǎn)換RedisSerializer<String> strSerializer = new StringRedisSerializer();Jackson2JsonRedisSerializer jacksonSeial =new Jackson2JsonRedisSerializer(Object.class);// 解決查詢緩存轉(zhuǎn)換異常的問題ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jacksonSeial.setObjectMapper(om);// 定制緩存數(shù)據(jù)序列化方式及時(shí)效RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(1)).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(strSerializer)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSeial)).disableCachingNullValues();RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).build();return cacheManager;} }

附錄

1.Assert:斷言機(jī)制:

測(cè)試代碼或者調(diào)試程序時(shí),總會(huì)做出一些假設(shè),斷言就是用于在代碼中捕捉這些假設(shè)。當(dāng)要判斷一個(gè)方法傳入的參數(shù)時(shí),我們就可以使用斷言。

public void isTest(){Assert.notNull(cart);Assert.notEmpty(cart.getCartItems());Assert.notNull(receiver);Assert.notNull(paymentMethod);Assert.notNull(shippingMethod);}

單詞

evaluate 評(píng)估
Definition定義
Enabled啟動(dòng)
Candidate候選人 ==》getCandidateConfigurations
Duplicate輔助 ==》removeDuplicates

deduce 推斷-==》deduceFromClasspath

primary主要,基本–》primarySources

Environment==》configureEnvironment

總結(jié)

以上是生活随笔為你收集整理的SpringBoot源码笔记分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。