目錄
如何實現一個IOC容器?
說說你對Spring 的理解?
你覺得Spring的核心是什么?
說一下使用spring的優勢?
Spring是如何簡化開發的?
IOC 運行時序
prepareRefresh()??初始化上下文環境
obtainFreshBeanFactory()? ?創建并初始化 BeanFactory
prepareBeanFactory(beanFactory)??填充 BeanFactory 功能
postProcessBeanFactory()??提供子類覆蓋的額外處理
invokeBeanFactoryPostProcessors()? ? 激活各種BeanFactory處理器
registerBeanPostProcessors
initMessageSource
initApplicationEventMulticaster
onRefresh
registerListeners
finishBeanFactoryInitialization
finishRefresh
Spring的AOP的底層實現原理
說說你對Aop的理解?
說說你對IOC的理解?
依賴注入DI 的概念
談一下spring IOC的底層實現
BeanFactory和ApplicationContext有什么區別
簡述spring bean的生命周期?
spring支持的bean作用域有哪些?
Spring框架中的單例Bean是線程安全的么?
spring框架中使用了哪些設計模式及應用場景
spring事務的實現方式原理是什么?
Transaction失效
spring事務的隔離級別有哪些?
spring的事務傳播機制是什么?
spring事務什么時候會失效?
什么的是bean的自動裝配,它有哪些方式?
spring是如何解決循環依賴的
不能解決的幾種循環依賴
pring中常見的幾種注解
spring、springmvc、springboot的區別是什么?
springmvc工作流程是什么?
springmvc的九大組件有哪些?
Spring框架中有哪些不同類型的事件
如何實現一個IOC容器?
要實現一個簡單的Spring框架IOC容器,您可以遵循以下步驟:
-
定義Bean注解: 創建一個自定義的注解,例如
@MyBean
,用于標識需要被IOC容器管理的Bean類。 -
掃描并解析Bean定義:(BeanDefinition) 創建一個Bean解析器,用于掃描應用程序中的所有類,解析帶有
@MyBean
注解的類,并存儲Bean的定義信息,如類名、屬性等。 -
創建Bean實例: 根據Bean定義信息,使用反射機制實例化Bean,并進行依賴注入。遍歷所有的Bean定義,根據類名使用反射創建Bean實例,并解析其屬性依賴關系,將相應的依賴注入到實例中。
-
實現依賴注入: 當創建Bean實例時,解析Bean的屬性依賴關系,并根據依賴注入的方式,通過反射或者setter方法將需要的依賴注入到Bean實例中。
-
管理Bean的生命周期: 可以在Bean中定義初始化和銷毀方法,并在容器中調用這些方法來管理Bean的生命周期。可以使用
@PostConstruct
注解標注初始化方法,使用@PreDestroy
注解標注銷毀方法。 -
提供獲取Bean的方法: 在IOC容器中提供一個方法,根據Bean的名稱獲取對應的實例。可以使用Map來存儲Bean實例,key為Bean的名稱,value為實例對象。
-
實現配置文件加載: 可以實現一個簡單的配置文件加載機制,從配置文件中讀取需要注入的屬性值,例如使用properties文件或者XML文件。
以上是一個簡單的實現Spring框架IOC容器的步驟。在實際的Spring框架中,還有更多復雜的功能和特性,如AOP、循環依賴處理、Bean的作用域、配置文件的自動裝配等。這些是更高級的功能,需要更復雜的設計和實現。但通過上述步驟,您可以實現一個簡單的IOC容器,理解IOC的基本概念和實現原理。
說說你對Spring 的理解?
官網地址:Spring Framework
壓縮包下載地址:JFrog
源碼地址:GitHub - spring-projects/spring-framework: Spring Framework
Spring makes it easy to create Java enterprise applications. It provides everything you need to embrace the Java language in an enterprise environment, with support for Groovy and Kotlin as alternative languages on the JVM, and with the flexibility to create many kinds of architectures depending on an application’s needs. As of Spring Framework 5.1, Spring requires JDK 8+ (Java SE 8+) and provides out-of-the-box support for JDK 11 LTS. Java SE 8 update 60 is suggested as the minimum patch release for Java 8, but it is generally recommended to use a recent patch release. ? Spring supports a wide range of application scenarios. In a large enterprise, applications often exist for a long time and have to run on a JDK and application server whose upgrade cycle is beyond developer control. Others may run as a single jar with the server embedded, possibly in a cloud environment. Yet others may be standalone applications (such as batch or integration workloads) that do not need a server. ? Spring is open source. It has a large and active community that provides continuous feedback based on a diverse range of real-world use cases. This has helped Spring to successfully evolve over a very long time. ? Spring 是一個開源的輕量級企業應用開發框架,它提供了廣泛的基礎設施支持和生命周期管理,用于幫助開發人員構建企業級應用程序。以下是我對 Spring 的理解:1. IoC(Inverse of Control,控制反轉)容器: Spring 使用 IoC 容器管理應用程序中的對象依賴關系,通過將對象的創建、配置和組裝過程由開發者轉移到 Spring 容器,降低了組件之間的耦合度。2. AOP(Aspect-Oriented Programming,面向切面編程)支持: Spring 提供了 AOP 配置和支持,可以將橫切關注點(cross-cutting concerns)從核心業務邏輯中分離出來,實現了橫切關注點的重用和集中管理。3. **聲明式事務管理:** Spring 提供了強大的事務管理支持,可以通過聲明式的方式管理事務,簡化了事務管理的實現,同時提供了靈活性和可定制性。4. 模塊化設計: Spring 框架被設計為多個模塊組成,每個模塊都提供了特定的功能,開發者可以根據需求選擇使用相應模塊,從而減少了不必要的資源浪費。5. 簡化企業級開發: Spring 提供了大量的企業級功能的封裝和支持,如數據訪問、事務管理、安全性、消息傳遞等,大大簡化了開發人員構建企業級應用程序的工作量。6. 持續演進和創新: Spring 框架不斷進行演進和創新,持續引入新的功能和特性,以適應不斷變化的開發需求和技術趨勢。總的來說,Spring 框架提供了一套全面且靈活的解決方案,幫助開發人員簡化企業級應用程序的開發和維護工作,提高了代碼的可維護性、可測試性和整體質量。通過合理使用 Spring 框架,開發人員可以專注于業務邏輯的實現,而不必過多關注底層技術細節。
你覺得Spring的核心是什么?
Spring是一個開源的Java框架,用于構建企業級的應用程序。它提供了一個容器,用于管理應用程序中的對象(如依賴注入)并提供了許多常用的功能和擴展,使開發人員能夠更加專注于業務邏輯的實現而不必關注太多的底層細節。
Spring的核心特性包括:
-
控制反轉(IoC):Spring使用控制反轉來實現依賴注入。控制反轉意味著對于對象的創建和依賴關系的管理由容器來完成,而不是由開發人員手動處理。這種方式可以降低組件之間的耦合度,并且使得代碼更加靈活和易于擴展。
-
面向切面編程(AOP):Spring提供了面向切面編程的支持,可以通過AOP將橫切關注點(如日志、事務管理)從業務邏輯中分離出來,使得代碼更具可維護性和可讀性。
-
集成框架:Spring可以與各種其他框架和技術進行集成,如持久化框架(Hibernate、MyBatis)、消息隊列(ActiveMQ、RabbitMQ)、Web框架(Spring MVC)等,以便于開發人員在項目中使用更多的功能和工具。
總之,Spring框架提供了一種靈活、高效的開發方式,可以幫助開發人員構建可擴展、可維護的企業級應用程序。它的特性和擴展使得它在Java開發社區中非常流行和廣泛使用。
說一下使用spring的優勢?
使用Spring框架具有許多優勢,它是一個強大的企業級應用程序開發框架,提供了廣泛的功能和特性。下面是一些使用Spring框架的優勢:
-
面向切面編程(AOP):Spring支持AOP,使你能夠以聲明性的方式處理跨多個模塊的關注點(例如事務管理、安全性、日志記錄等),提高了代碼的模塊化和可維護性。
-
依賴注入(DI):Spring的核心功能是依賴注入,它將組件之間的依賴關系轉移給容器來管理。這種松耦合的設計使得代碼更靈活、可測試性更強,并降低了代碼的耦合度。
-
面向接口編程:Spring鼓勵使用面向接口的編程風格,通過接口定義了各種組件之間的契約,使得代碼更易于擴展和修改,并提供了解耦的效果。
-
組件化開發:Spring鼓勵使用組件化開發的思想,將應用程序拆分為功能模塊化的組件,每個組件負責特定的功能。這種模塊化的設計使得應用程序更容易理解、擴展和維護。
-
輕量級和可擴展性:Spring框架本身非常輕量級,不需要很大的資源開銷。同時,Spring提供了許多可選的模塊和擴展,可以根據需求進行選擇和集成,實現高度可定制的應用程序開發。
-
寬松的集成:Spring集成了許多其他流行的開源框架和技術,例如Hibernate、JPA、MyBatis、Spring MVC、Spring Boot等。這種寬松的集成能力使得開發人員可以根據自己的需求選擇不同的技術和工具。
-
安全性:Spring提供了一套全面的安全性功能,包括身份認證、訪問控制和加密等。這些功能可以幫助開發人員構建安全可靠的應用程序。
總的來說,Spring框架的優勢在于提供了一種靈活、模塊化、可擴展和高度定制的方式來開發企業級應用程序。它促進了良好的設計原則和最佳實踐,提高了開發效率和代碼質量。同時,Spring擁有龐大的社區支持和廣泛的文檔資源,使開發人員能夠輕松學習和解決問題。
Spring是如何簡化開發的?
Spring框架通過依賴注入、面向切面編程、組件化開發、技術整合和豐富的功能模塊,簡化了企業級應用程序的開發過程。它提供了一種靈活、模塊化、可擴展和高度定制的方式來開發應用程序,提高了開發效率和代碼質量。
IOC 運行時序
當調用 ApplicationContext 的 refresh() 方法時,Spring 容器將執行以下一系列步驟以完成初始化過程:
原文鏈接:【死磕 Spring】----- 深入分析 ApplicationContext 的 refresh()_為什么applicationcontext1.refresh();-CSDN博客
當調用 ApplicationContext 的 refresh() 方法時,Spring 容器將執行以下一系列步驟以完成初始化過程:
@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 準備刷新上下文環境prepareRefresh();
?// 創建并初始化 BeanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
?// 填充BeanFactory功能prepareBeanFactory(beanFactory);
?try {// 提供子類覆蓋的額外處理,即子類處理自定義的BeanFactoryPostProcesspostProcessBeanFactory(beanFactory);
?// 激活各種BeanFactory處理器invokeBeanFactoryPostProcessors(beanFactory);
?// 注冊攔截Bean創建的Bean處理器,即注冊 BeanPostProcessorregisterBeanPostProcessors(beanFactory);
?// 初始化上下文中的資源文件,如國際化文件的處理等initMessageSource();
?// 初始化上下文事件廣播器initApplicationEventMulticaster();
?// 給子類擴展初始化其他BeanonRefresh();
?// 在所有bean中查找listener bean,然后注冊到廣播器中registerListeners();
?// 初始化剩下的單例Bean(非延遲加載的)finishBeanFactoryInitialization(beanFactory);
?// 完成刷新過程,通知生命周期處理器lifecycleProcessor刷新過程,同時發出ContextRefreshEvent通知別人finishRefresh();}
?catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}
?// 銷毀已經創建的BeandestroyBeans();
?// 重置容器激活標簽cancelRefresh(ex);
?// 拋出異常throw ex;}
?finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}
}
prepareRefresh()??初始化上下文環境
初始化上下文環境,對系統的環境變量或者系統屬性進行準備和校驗,如環境變量中必須設置某個值才能運行,否則不能運行,這個時候可以在這里加這個校驗,重寫initPropertySources方法就好了
該方法主要是做一些準備工作,如:
-
設置 context 啟動時間
-
設置 context 的當前狀態
-
初始化 context environment 中占位符
-
對屬性進行必要的驗證
obtainFreshBeanFactory()? ?創建并初始化 BeanFactory
創建并初始化 BeanFactory
核心方法就在 refreshBeanFactory()
,該方法的核心任務就是創建 BeanFactory 并對其就行一番初始化。如下:
protected final void refreshBeanFactory() throws BeansException {if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {DefaultListableBeanFactory beanFactory = createBeanFactory();beanFactory.setSerializationId(getId());customizeBeanFactory(beanFactory);loadBeanDefinitions(beanFactory);synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}
}
判斷當前容器是否存在一個 BeanFactory,如果存在則對其進行銷毀和關閉 調用 createBeanFactory() 創建一個 BeanFactory 實例,其實就是 DefaultListableBeanFactory 自定義 BeanFactory 加載 BeanDefinition loadBeanDefinitions()
是定義在 BeanDefinitionReader
將創建好的 bean 工廠的引用交給的 context 來管理
prepareBeanFactory(beanFactory)??填充 BeanFactory 功能
上面獲取獲取的 BeanFactory 除了加載了一些 BeanDefinition 就沒有其他任何東西了,這個時候其實還不能投入生產,因為還少配置了一些東西,比如 context的 ClassLoader 和 后置處理器等等。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// 設置beanFactory的classLoaderbeanFactory.setBeanClassLoader(getClassLoader());// 設置beanFactory的表達式語言處理器,Spring3開始增加了對語言表達式的支持,默認可以使用#{bean.xxx}的形式來調用相關屬性值beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));// 為beanFactory增加一個默認的propertyEditorbeanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));// 添加ApplicationContextAwareProcessorbeanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));// 設置忽略自動裝配的接口beanFactory.ignoreDependencyInterface(EnvironmentAware.class);beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);// 設置幾個自動裝配的特殊規則beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);// Register early post-processor for detecting inner beans as ApplicationListeners.beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));// 增加對AspectJ的支持if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));// Set a temporary ClassLoader for type matching.beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}// 注冊默認的系統環境beanif (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());}if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());}if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());}
postProcessBeanFactory()??提供子類覆蓋的額外處理
提供子類覆蓋的額外處理,即子類處理自定義的BeanFactoryPostProcess
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));beanFactory.ignoreDependencyInterface(ServletContextAware.class);beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
?WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
添加 ServletContextAwareProcessor 到 BeanFactory 容器中,該 processor 實現 BeanPostProcessor 接口,主要用于將ServletContext 傳遞給實現了 ServletContextAware 接口的 bean 忽略 ServletContextAware、ServletConfigAware 注冊 WEB 應用特定的域(scope)到 beanFactory 中,以便 WebApplicationContext 可以使用它們。比如 “request” , “session” , “globalSession” , “application” 注冊 WEB 應用特定的 Environment bean 到 beanFactory 中,以便WebApplicationContext 可以使用它們。如:“contextParameters”, “contextAttributes”
invokeBeanFactoryPostProcessors()? ? 激活各種BeanFactory處理器
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
?// 定義一個 set 保存所有的 BeanFactoryPostProcessorsSet<String> processedBeans = new HashSet<>();
?// 如果當前 BeanFactory 為 BeanDefinitionRegistryif (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;// BeanFactoryPostProcessor 集合List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();// BeanDefinitionRegistryPostProcessor 集合List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
?// 迭代注冊的 beanFactoryPostProcessorsfor (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {// 如果是 BeanDefinitionRegistryPostProcessor,則調用 postProcessBeanDefinitionRegistry 進行注冊,// 同時加入到 registryProcessors 集合中if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;registryProcessor.postProcessBeanDefinitionRegistry(registry);registryProcessors.add(registryProcessor);}else {// 否則當做普通的 BeanFactoryPostProcessor 處理// 添加到 regularPostProcessors 集合中即可,便于后面做后續處理regularPostProcessors.add(postProcessor);}}
?// 用于保存當前處理的 BeanDefinitionRegistryPostProcessorList<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
?// 首先處理實現了 PriorityOrdered (有限排序接口)的 BeanDefinitionRegistryPostProcessorString[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}
?// 排序sortPostProcessors(currentRegistryProcessors, beanFactory);
?// 加入registryProcessors集合registryProcessors.addAll(currentRegistryProcessors);
?// 調用所有實現了 PriorityOrdered 的 BeanDefinitionRegistryPostProcessors 的 postProcessBeanDefinitionRegistry()invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
?// 清空,以備下次使用currentRegistryProcessors.clear();
?// 其次,調用是實現了 Ordered(普通排序接口)的 BeanDefinitionRegistryPostProcessors// 邏輯和 上面一樣postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();
?// 最后調用其他的 BeanDefinitionRegistryPostProcessorsboolean reiterate = true;while (reiterate) {reiterate = false;// 獲取 BeanDefinitionRegistryPostProcessorpostProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {
?// 沒有包含在 processedBeans 中的(因為包含了的都已經處理了)if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}
?// 與上面處理邏輯一致sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}
?// 調用所有 BeanDefinitionRegistryPostProcessor (包括手動注冊和通過配置文件注冊)// 和 BeanFactoryPostProcessor(只有手動注冊)的回調函數(postProcessBeanFactory())invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}
?else {// 如果不是 BeanDefinitionRegistry 只需要調用其回調函數(postProcessBeanFactory())即可invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}
?//String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
?// 這里同樣需要區分 PriorityOrdered 、Ordered 和 no OrderedList<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {// 已經處理過了的,跳過if (processedBeans.contains(ppName)) {// skip - already processed in first phase above}// PriorityOrderedelse if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}// Orderedelse if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}// no Orderedelse {nonOrderedPostProcessorNames.add(ppName);}}
?// First, PriorityOrdered 接口sortPostProcessors(priorityOrderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
?// Next, Ordered 接口List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
?// Finally, no orderedList<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
?// Clear cached merged bean definitions since the post-processors might have// modified the original metadata, e.g. replacing placeholders in values...beanFactory.clearMetadataCache();
}
上述代碼較長,但是處理邏輯較為單一,就是對所有的 BeanDefinitionRegistryPostProcessors 、手動注冊的 BeanFactoryPostProcessor 以及通過配置文件方式的 BeanFactoryPostProcessor 按照 PriorityOrdered 、 Ordered、no ordered 三種方式分開處理、調用。
registerBeanPostProcessors
注冊攔截Bean創建的Bean處理器,即注冊 BeanPostProcessor
與 BeanFactoryPostProcessor 一樣,也是委托給 PostProcessorRegistrationDelegate 來實現的。
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { ?// 所有的 BeanPostProcessorsString[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); ?// 注冊 BeanPostProcessorChecker// 主要用于記錄一些 bean 的信息,這些 bean 不符合所有 BeanPostProcessors 處理的資格時int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); ?// 區分 PriorityOrdered、Ordered 、 no orderedList<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();// MergedBeanDefinitionList<BeanPostProcessor> internalPostProcessors = new ArrayList<>();for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);priorityOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}} ?// First, PriorityOrderedsortPostProcessors(priorityOrderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); ?// Next, OrderedList<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();for (String ppName : orderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);orderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}sortPostProcessors(orderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, orderedPostProcessors); ?// onOrderedList<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();for (String ppName : nonOrderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);nonOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); ?// Finally, all internal BeanPostProcessors.sortPostProcessors(internalPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, internalPostProcessors); ?// 重新注冊用來自動探測內部ApplicationListener的post-processor,這樣可以將他們移到處理器鏈條的末尾beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext)); }
initMessageSource
初始化上下文中的資源文件,如國際化文件的處理等
initApplicationEventMulticaster
初始化上下文事件廣播器
onRefresh
給子類擴展初始化其他Bean
預留給 AbstractApplicationContext 的子類用于初始化其他特殊的 bean,該方法需要在所有單例 bean 初始化之前調用。
registerListeners
在所有 bean 中查找 listener bean,然后注冊到廣播器中
protected void registerListeners() {// 注冊靜態 監聽器for (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}
?String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}
?// 至此,已經完成將監聽器注冊到ApplicationEventMulticaster中,下面將發布前期的事件給監聽器。Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (earlyEventsToProcess != null) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent);}}
}
finishBeanFactoryInitialization
初始化剩下的單例Bean(非延遲加載的)
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// 初始化轉換器if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));}
?// 如果之前沒有注冊 bean 后置處理器(例如PropertyPlaceholderConfigurer),則注冊默認的解析器if (!beanFactory.hasEmbeddedValueResolver()) {beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));}
?// 初始化 Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);for (String weaverAwareName : weaverAwareNames) {getBean(weaverAwareName);}
?// 停止使用臨時的 ClassLoaderbeanFactory.setTempClassLoader(null);
?//beanFactory.freezeConfiguration();
?// 初始化所有剩余的單例(非延遲初始化)beanFactory.preInstantiateSingletons();
}
finishRefresh
完成刷新過程,通知生命周期處理器 lifecycleProcessor 刷新過程,同時發出 ContextRefreshEvent 通知別人
主要是調用 LifecycleProcessor#onRefresh() ,并且發布事件(ContextRefreshedEvent)。
protected void finishRefresh() {// Clear context-level resource caches (such as ASM metadata from scanning).clearResourceCaches();
?// Initialize lifecycle processor for this context.initLifecycleProcessor();
?// Propagate refresh to lifecycle processor first.getLifecycleProcessor().onRefresh();
?// Publish the final event.publishEvent(new ContextRefreshedEvent(this));
?// Participate in LiveBeansView MBean, if active.LiveBeansView.registerApplicationContext(this);
}
Spring的AOP的底層實現原理
bean的創建過程中有一個步驟可以對bean進行擴展實現,aop本身就是一個擴展功能,所以在BeanPostProcessor的后置處理方法中來進行實現
不論使用哪種方式,Spring AOP的實現過程都包括以下幾個關鍵步驟:
-
定義切點(Pointcut):切點定義了在何處應用切面邏輯的具體位置。通過表達式或注解等方式,確定應該被代理的目標方法或目標類。
-
編寫切面(Aspect):切面是具體的橫切邏輯實現,包括在目標方法執行前后執行的操作(通知,Advices)。切面可以包括一個或多個通知的定義。
-
創建代理對象:Spring根據切點和切面信息,生成動態代理或字節碼增強的代理對象。代理對象在執行目標方法時,會根據切點和切面定義,執行相應的切面邏輯。
總結來說,Spring AOP的底層實現原理是通過動態代理或字節碼生成,將切面邏輯織入到目標對象或目標類中,實現橫切關注點的解耦和重用。
3.在執行方法調用的時候,會調用到生成的字節碼文件中,直接回找到DynamicAdvisoredInterceptor類中的intercept方法,從此方法開始執行
4.根據之前定義好的通知來生成攔截器
5.從攔截器鏈中依次獲取每一個通知開始進行執行,在執行過程中,為了方便找到下一個通知是哪個,會有一個CglibMethodInvocation的對象,找的時候是從-1的位置依次開始查找并且執行的。
說說你對Aop的理解?
AOP全稱叫做 Aspect Oriented Programming 面向切面編程。它是為解耦而生的,解耦是程序員編碼開發過程中一直追求的境界,AOP在業務類的隔離上,絕對是做到了解耦,在這里面有幾個核心的概念:
-
切面(Aspect): 指關注點模塊化,這個關注點可能會橫切多個對象。事務管理是企業級Java應用中有關橫切關注點的例子。 在Spring AOP中,切面可以使用通用類基于模式的方式(schema-based approach)或者在普通類中以
@Aspect
注解(@AspectJ 注解方式)來實現。(Aspect作為一個模塊來組織Join point , PointCut來篩選要執行的連接點,Advice在切面的某個特定的連接點上執行的動作),(一個Aspect對應多個join point,一個joinPoint 有多個 advice) -
連接點(Join point): 在程序執行過程中某個特定的點,例如某個方法調用的時間點或者處理異常的時間點。在Spring AOP中,一個連接點總是代表一個方法的執行。
-
通知(Advice): 在切面的某個特定的連接點上執行的動作。通知有多種類型,包括“around”, “before” and “after”等等。通知的類型將在后面的章節進行討論。 許多AOP框架,包括Spring在內,都是以攔截器做通知模型的,并維護著一個以連接點為中心的攔截器鏈。
-
切點(Pointcut): 匹配連接點的斷言。通知和切點表達式相關聯,并在滿足這個切點的連接點上運行(例如,當執行某個特定名稱的方法時)。切點表達式如何和連接點匹配是AOP的核心:Spring默認使用AspectJ切點語義。
-
引入(Introduction): 聲明額外的方法或者某個類型的字段。Spring允許引入新的接口(以及一個對應的實現)到任何被通知的對象上。例如,可以使用引入來使bean實現
IsModified
接口, 以便簡化緩存機制(在AspectJ社區,引入也被稱為內部類型聲明(inter))。 -
目標對象(Target object): 被一個或者多個切面所通知的對象。也被稱作被通知(advised)對象。既然Spring AOP是通過運行時代理實現的,那么這個對象永遠是一個被代理(proxied)的對象。
-
AOP代理(AOP proxy):AOP框架創建的對象,用來實現切面契約(aspect contract)(包括通知方法執行等功能)。在Spring中,AOP代理可以是JDK動態代理或CGLIB代理。
-
織入(Weaving): 把切面連接到其它的應用程序類型或者對象上,并創建一個被被通知的對象的過程。這個過程可以在編譯時(例如使用AspectJ編譯器)、類加載時或運行時中完成。 Spring和其他純Java AOP框架一樣,是在運行時完成織入的。
這些概念都太學術了,如果更簡單的解釋呢,其實非常簡單:
任何一個系統都是由不同的組件組成的,每個組件負責一塊特定的功能,當然會存在很多組件是跟業務無關的,例如日志、事務、權限等核心服務組件,這些核心服務組件經常融入到具體的業務邏輯中,如果我們為每一個具體業務邏輯操作都添加這樣的代碼,很明顯代碼冗余太多,因此我們需要將這些公共的代碼邏輯抽象出來變成一個切面,然后注入到目標對象(具體業務)中去,AOP正是基于這樣的一個思路實現的,通過動態代理的方式,將需要注入切面的對象進行代理,在進行調用的時候,將公共的邏輯直接添加進去,而不需要修改原有業務的邏輯代碼,只需要在原來的業務邏輯基礎之上做一些增強功能即可。
說說你對IOC的理解?
在 Spring 中,IoC 是 Inversion of Control(控制反轉)的縮寫,是 Spring 框架的一個重要特性。IoC 的本質是將對對象的控制權從應用程序本身轉移到了框架或容器中,由容器來負責對象的創建、管理和注入依賴對象,從而降低了組件之間的耦合度,提高了代碼的可重用性和可測試性。在 Spring 中,IoC 容器負責管理應用程序中的對象及其之間的依賴關系,開發人員不再需要手動創建對象和管理對象之間的關聯關系,而是通過配置文件或注解告訴容器如何創建和組裝對象。IoC 容器負責實例化對象、注入依賴、生命周期管理等工作,開發人員只需要關注業務邏輯的實現,將對象的創建和依賴關系的管理交由容器來完成。在 Spring 中,IoC 容器主要有兩種實現方式:BeanFactory 和 ApplicationContext。1. **BeanFactory:** 是 Spring 框架的基礎容器,提供了基本的 IoC 功能,可以延遲加載(Lazy Loading)和按需注入(On-demand Injection)Bean,適合在資源有限的環境下使用。2. **ApplicationContext:** 是 BeanFactory 的擴展,提供了更多的企業級功能和特性,如國際化支持、事件傳播、AOP、聲明式事務管理等,適合大多數企業級應用程序使用。通過 IoC 容器,Spring 管理了應用程序中的所有對象,并負責解決對象之間的依賴關系,從而實現了代碼的松耦合、易于維護和測試的優勢。開發人員可以通過配置文件或注解,實現對象之間的依賴注入,讓 IoC 容器來負責對象創建和管理,提高了應用程序的靈活性和可擴展性。
依賴注入DI 的概念
DI 是 Dependency Injection(依賴注入)的縮寫,它是面向對象編程中的一種設計模式,在 Spring 框架中被廣泛應用。DI 是 IoC(控制反轉)的一種實現方式,通過依賴注入的方式來實現對象之間的解耦和管理依賴關系。
在 DI 中,對象不再負責創建或查找依賴的對象,而是將依賴關系注入到對象之中。這樣做的好處是提高了代碼的可維護性、可測試性和可擴展性,降低了對象之間的耦合度,使得代碼更加靈活和易于重用。
在 Spring 框架中,依賴注入可以通過構造函數注入、Setter 方法注入或字段注入等方式實現。開發人員可以通過配置文件(如 XML 配置文件)或注解來指定依賴關系,讓 Spring IoC 容器來實現依賴注入的過程。
依賴注入的三種主要類型包括:
1. **構造函數注入(Constructor Injection):** 通過在構造函數中注入依賴對象來實現依賴注入。
2. **Setter 方法注入(Setter Injection):** 通過 Setter 方法來設置依賴對象,實現依賴注入。
3. **字段注入(Field Injection):** 通過字段(屬性)注入的方式來注入依賴對象。
依賴注入能夠讓開發人員專注于業務邏輯的實現,而不必擔心對象之間的依賴關系,提高了代碼的可維護性和可測試性。通過 DI,Spring 框架實現了 IoC 容器的依賴管理功能,讓開發人員將對象之間的關系交給容器管理,實現了控制反轉的思想。
談一下spring IOC的底層實現
底層實現:工作原理,過程,數據結構,流程,設計模式,設計思想
你對他的理解和你了解過的實現過程
反射,工廠,設計模式,關鍵的幾個方法
createBeanFactory , getBean ,doGetBean , createBean , doCreateBean,createBeanInstance(getDeclaredConstructor(),newinstance),populateBean
1.先通過createBeanFactory 創建一個Bean工廠(DefaultListableBeanFactory)
2.開始循環創建對象,因為容器中的bean默認都是單例的,所以優先通過getBean,doGetBean從容器中查找,找不到的話,
3.通過createBean,doCreateBean方法,以反射的方式創建對象,一般情況下使用的是無參的構造器(getDeclaredConstructor(),newinstance)
4.進行對象的屬性填充populateBean
5.進行其他的初始化操作(initializingBean)
BeanFactory和ApplicationContext有什么區別
相同:
-
Spring提供了兩種不同的IOC 容器,一個是BeanFactory,另外一個是ApplicationContext,它們都是Java interface,ApplicationContext繼承于BeanFactory(ApplicationContext繼承ListableBeanFactory。
-
它們都可以用來配置XML屬性,也支持屬性的自動注入。
-
而ListableBeanFactory繼承BeanFactory),BeanFactory 和 ApplicationContext 都提供了一種方式,使用getBean("bean name")獲取bean。
不同:
BeanFactory和ApplicationContext是Spring框架中的兩個核心接口,它們具有以下區別:
-
功能:
-
BeanFactory是Spring的最基本的接口,提供了IoC容器的基本功能,即管理和獲取Bean。
-
ApplicationContext是對BeanFactory的擴展,提供了更多的功能,如國際化支持、事件發布、資源加載、AOP等。
-
-
預加載:
-
BeanFactory是延遲加載的,即在調用
getBean()
方法時才會創建和初始化Bean。 -
ApplicationContext可以通過配置進行預加載,即在容器啟動時就實例化和初始化所有的單例Bean。
-
-
配置元數據的處理:
-
BeanFactory使用BeanDefinition來管理和解析配置元數據,Bean的創建由BeanDefinition中的信息描述。
-
ApplicationContext在BeanFactory的基礎上進一步擴展了對配置元數據的處理,提供更高級的功能,如自動掃描、注解驅動等。
-
-
Spring AOP:
-
BeanFactory需要手動將AspectJ代理工廠(AspectJProxyFactory)應用于Bean,才能支持Spring AOP。
-
ApplicationContext自動為Bean提供代理,支持Spring AOP。
-
-
國際化支持:
-
ApplicationContext提供了更方便的國際化(i18n)支持,可以基于
ResourceBundle
實現多語言切換。
-
總的來說,BeanFactory是更基礎的接口,提供了最基本的IoC容器功能;而ApplicationContext是BeanFactory的擴展,提供了更多的功能和便利性,是在實際應用中更常用的接口。如果需要更完整的功能,如AOP、國際化、事件發布等,那么建議使用ApplicationContext。但是,如果對資源要求較低,且只需要基本的Bean管理功能,可以使用BeanFactory來獲得更輕量級的容器。
簡述spring bean的生命周期?
-
實例化(Instantiation):
-
Bean的實例化是通過構造函數或工廠方法創建的。
-
可以在此階段進行一些前置處理,容器會在初始化Bean之前先調用BeanPostProcessor的postProcessBeforeInitialization()方法。
-
-
屬性設置(Population):
-
Spring通過依賴注入(DI)將Bean的屬性進行設置。
-
可以在此階段進行一些屬性相關的操作,如使用
@Autowired
、@Value
等注解進行屬性注入和賦值。
-
-
初始化(Initialization):
-
在Bean的所有屬性被設置完后,可以執行自定義的初始化邏輯。
-
可以通過實現
InitializingBean
接口的afterPropertiesSet
方法或使用@PostConstruct
注解進行初始化操作。 -
可以在此階段進行一些初始化相關的操作,如連接數據庫、讀取配置文件等。
-
BeanPostProcessor的后置處理:如果在容器中定義了BeanPostProcessor,容器會在初始化Bean之后調用BeanPostProcessor的postProcessAfterInitialization()方法。
-
-
使用(In Use):
-
Bean可以在應用程序中正常使用,處理業務邏輯。
-
Bean會一直處于使用狀態,直到應用程序關閉或Bean被銷毀。
-
-
銷毀(Destruction):
-
當應用程序關閉或手動銷毀Bean時,會執行銷毀階段的邏輯。
-
可以通過實現
DisposableBean
接口的destroy
方法或使用@PreDestroy
注解進行銷毀操作。 -
可以在此階段進行一些資源釋放、清理工作,如關閉數據庫連接、釋放文件句柄等。
-
值得注意的是,對于單例作用域的Bean,默認情況下,Spring容器在啟動時會將所有單例Bean進行實例化和初始化,并在容器關閉時銷毀它們;而對于原型作用域的Bean,Spring容器僅負責實例化和初始化,不負責銷毀,需要由調用者自行管理。
通過在Bean上實現相應的接口或使用注解,可以對Bean的生命周期進行自定義操作,從而滿足應用程序的需求。
spring支持的bean作用域有哪些?
-
Singleton(默認):
-
單例作用域,每個Spring容器只創建一個實例。
-
多個Bean引用同一個實例。
-
適用于無狀態的Bean和共享資源的情況。
-
-
Prototype:
-
原型作用域,每次從容器中獲取Bean時都會創建一個新的實例。
-
每個Bean引用不同的實例。
-
適用于有狀態的Bean和非共享資源的情況。
-
-
Request:
-
請求作用域,每個HTTP請求都會創建一個新的實例。
-
每個請求期間的所有Bean引用同一個實例。
-
適用于Web應用程序中需要在每個請求期間共享數據的情況。
-
-
Session:
-
會話作用域,每個用戶會話都會創建一個新的實例。
-
每個用戶會話期間的所有Bean引用同一個實例。
-
適用于Web應用程序中需要在每個用戶會話期間共享數據的情況。
-
-
Global session(僅適用于Portlet環境):
-
全局會話作用域,每個Portlet應用程序的全局會話都會創建一個新的實例。
-
每個全局會話期間的所有Bean引用同一個實例。
-
-
WebSocket(僅適用于WebSocket環境):
-
WebSocket作用域,每個WebSocket會話都會創建一個新的實例。
-
每個WebSocket會話期間的所有Bean引用同一個實例。
-
可以通過在Spring的Bean聲明中使用@Scope
注解或在XML配置文件中使用<bean>
元素的scope
屬性來設置Bean的作用域。例如:
@Component @Scope("prototype") public class MyPrototypeBean {// ... }
或者在XML配置中:
<bean id="myPrototypeBean" class="com.example.MyPrototypeBean" scope="prototype"/>
根據應用程序的需求,選擇適合的作用域可以更好地控制Bean的生命周期和資源管理。
Spring框架中的單例Bean是線程安全的么?
spring只是一中容器,需要看有沒有對bean進行多線程處理
Spring中的Bean對象默認是單例的,框架并沒有對bean進行多線程的封裝處理
如果Bean是有狀態的
無狀態就是不會存儲數據,你想一下,我們的controller,service和dao本身并不是線程安全的,只是調用里面的方法,而且多線程調用一個實例的方法,會在內存中復制遍歷,這是自己線程的工作內存,是最安全的。
因此在進行使用的時候,不要在bean中聲明任何有狀態的實例變量或者類變量,如果必須如此,也推薦大家使用ThreadLocal把變量變成線程私有,如果bean的實例變量或者類變量需要在多個線程之間共享,那么就只能使用synchronized,lock,cas等這些實現線程同步的方法了。
spring框架中使用了哪些設計模式及應用場景
1.工廠模式,在各種BeanFactory以及ApplicationContext創建中都用到了
2.模版模式,在各種BeanFactory以及ApplicationContext實現中也都用到了
3.代理模式,Spring AOP 利用了 AspectJ AOP實現的! AspectJ AOP 的底層用了動態代理
4.策略模式,加載資源文件的方式,使用了不同的方法,比如:ClassPathResourece,FileSystemResource,ServletContextResource,UrlResource但他們都有共同的借口Resource;在Aop的實現中,采用了兩種不同的方式,JDK動態代理和CGLIB代理
5.單例模式,比如在創建bean的時候。
6.觀察者模式,spring中的ApplicationEvent,ApplicationListener,ApplicationEventPublisher
7.適配器模式,MethodBeforeAdviceAdapter,ThrowsAdviceAdapter,AfterReturningAdapter
8.裝飾者模式,源碼中類型帶Wrapper或者Decorator的都是
spring事務的實現方式原理是什么?
在使用Spring框架的時候,可以有兩種事務的實現方式,一種是編程式事務,有用戶自己通過代碼來控制事務的處理邏輯,還有一種是聲明式事務,通過@Transactional注解來實現。
在 Spring 中,事務的實現方式主要依賴于兩個核心概念:事務管理器(Transaction Manager)和代理模式。
-
事務管理器(Transaction Manager):Spring 提供了多個事務管理器的實現,例如 DataSourceTransactionManager、JpaTransactionManager 等。事務管理器負責管理事務的開始、提交、回滾等操作。它與底層的數據庫、ORM 框架或其他事務資源進行交互,確保事務的正確執行。
-
代理模式:Spring 使用 AOP(面向切面編程)和代理模式來實現事務。當方法被標注為事務性時,Spring 會動態地生成一個代理類來包裝該方法,代理類負責增加額外的邏輯,如事務的管理。
工作原理如下:
-
通過配置事務管理器,將其與當前的數據源或其他事務資源進行關聯。
-
在配置文件或注解中對需要進行事務管理的方法進行標注 @Transactional。
-
當標注的方法被調用時,Spring 會通過動態代理機制生成一個代理類,并在代理類中添加事務管理的邏輯。代理類會攔截方法的調用,并在方法執行前后執行事務的開啟、提交或回滾等操作。
-
根據配置的事務屬性,事務管理器會根據方法的執行結果決定事務的提交或回滾。
具體的實現機制包括:
-
事務的劃分:通過注解或配置方式,標識哪些方法需要進行事務管理。
-
事務的邊界控制:Spring 會在適當的時機開始一個事務(如方法開始時)和結束一個事務(如方法結束時)。
-
事務的隔離級別與傳播行為控制:通過設置事務的隔離級別(如讀未提交、讀已提交等)和傳播行為(如支持當前事務、新建事務等),對事務進行精確控制。
-
異常處理與事務回滾:對于出現異常的情況,根據配置的事務屬性決定是否回滾事務。如果方法內部拋出了受檢查異常,Spring 默認會回滾事務;如果拋出非受檢查異常,則根據異常類型決定是否回滾。
通過以上的機制和流程,Spring 能夠提供基于代理的事務管理功能,將事務的管理與具體業務邏輯解耦,使得事務管理更加靈活、方便和可控。
Transaction失效
1、bean對象沒有被spring容器管理
2、方法的訪問修飾符不是public
3、自身調用問題
4、數據源沒有配置事務管理器
5、數據庫不支持事務
6、異常被捕獲
7、異常類型錯誤或者配置錯誤
spring事務的隔離級別有哪些?
spring中的事務隔離級別就是數據庫的隔離級別,有以下幾種:
read uncommitted
read committed
repeatable read
serializable
在進行配置的時候,如果數據庫和spring代碼中的隔離級別不同,那么以spring的配置為主。
spring的事務傳播機制是什么?
Spring的事務傳播(Transaction Propagation)機制定義了在多個事務方法相互調用時,事務是如何傳播和管理的。事務傳播機制主要用于控制事務的邊界和隔離級別,以保證數據的一致性和完整性。
Spring框架定義了以下幾種事務傳播行為:
1、propagation_required:支持當前事務,無事務,另起新事物
2、propagation_required-new:新建事務,若有舊事務,掛起。
3、propagation_supports:支持當前事務,無事務,以非事務執行
4、propagation_mandatory:以事務方式執行,無事務,拋異常
5、propagation_not_supported:不支持事務,如有事務,掛起
6、propagation_never:以非事務執行,有事務,拋異常
7、propagation_nested:內切事務
這些事務傳播行為可以通過在方法上使用 @Transactional
注解來指定。例如:
@Transactional(propagation = Propagation.REQUIRED) public void doSomething() {// 執行業務邏輯 }
需要注意的是,事務的傳播行為只在嵌套方法調用中生效,對于同一個類中的不同方法調用,事務傳播行為不起作用。在開發過程中,根據業務需求和實際情況選擇適合的事務傳播行為可以有效地保證數據的一致性和完整性。
NESTED和REQUIRED_NEW的區別:
REQUIRED_NEW是新建一個事務并且新開始的這個事務與原有事務無關,而NESTED則是當前存在事務時會開啟一個嵌套事務,在NESTED情況下,父事務回滾時,子事務也會回滾,而REQUIRED_NEW情況下,原有事務回滾,不會影響新開啟的事務
NESTED和REQUIRED的區別:
REQUIRED情況下,調用方存在事務時,則被調用方和調用方使用同一個事務,那么被調用方出現異常時,由于共用一個事務,所以無論是否catch異常,事務都會回滾,而在NESTED情況下,被調用方發生異常時,調用方可以catch其異常,這樣只有子事務回滾,父事務不會回滾。
spring事務什么時候會失效?
在Spring框架中,事務的失效可能由以下情況引起:
-
未開啟事務:在方法上沒有使用
@Transactional
注解或在XML配置中未配置事務管理器和事務攔截器時,事務將不會開啟,即使方法中出現數據庫操作也不會有事務支持。 -
異常未被捕獲:當在事務范圍內的方法拋出未被捕獲的異常時,默認情況下事務將回滾。但是,如果異常被捕獲并處理(例如通過try-catch塊),那么事務將不會回滾。
-
不受事務管理的方法調用:如果在具有事務的方法內部調用了另一個沒有使用
@Transactional
注解的方法,則被調用方法不會繼承事務,即事務將被掛起,它將在調用返回后恢復。 -
事務邊界不一致:當在一個方法中通過注解配置的事務與使用編程式事務管理方式(通過
TransactionTemplate
或PlatformTransactionManager
)管理的事務混合使用時,事務可能會失效。這是因為Spring無法同時應用兩種不同的事務管理方式。 -
ThreadLocal問題:如果使用了并發編程中的ThreadLocal,例如在事務中使用了ThreadLocal保存狀態,那么在多線程環境下,由于線程切換可能導致線程間的狀態共享問題,從而破壞了事務的一致性。
-
方法級別的調用問題:如果在同一個類中的一個使用
@Transactional
注解的方法調用了同一個類中另一個沒有使用注解的方法,事務將無法正常生效,因為Spring使用代理對象來管理事務,而調用同一個類中的方法將不會經過代理,導致事務失效。
需注意的是,事務失效并不是Spring框架的設計缺陷,而是由于使用不當或特定的情況下引起的。為了確保事務的正常工作,請確保在使用事務時遵循相關的最佳實踐,并注意上述可能導致事務失效的情況。
什么的是bean的自動裝配,它有哪些方式?
Bean的自動裝配是指Spring容器在創建Bean時,自動地根據特定規則在上下文中尋找匹配的依賴項,并將其注入到Bean中。這樣可以減少配置文件的編寫,提高開發效率,減少開發人員的工作量。
Spring框架支持以下幾種Bean的自動裝配方式:
1. **no(默認):** 不使用自動裝配,手動指定依賴注入的方式(通過構造器、setter方法等)。
2. **byName:** 根據bean的名稱進行自動裝配,Spring容器在上下文中查找與屬性名稱匹配的bean,然后進行注入。
3. **byType:** 根據bean的類型進行自動裝配,Spring容器在上下文中查找與屬性類型匹配的bean,然后進行注入。如果匹配的bean有多個,則拋出異常。
4. **constructor:** 類似于byType,但是是應用于構造器參數的自動裝配方式。
5. **autodetect:** Spring根據情況自動選擇合適的自動裝配方式,該方式會先byType,如果找不到則會byName。
自動裝配可以通過在XML配置文件中的`<bean>`標簽的`autowire`屬性來指定,也可以通過使用注解(如`@Autowired`、`@Resource`)來實現。在XML配置文件中使用自動裝配的示例如下:
```xml
<bean id="beanA" class="com.example.BeanA" autowire="byName|byType|constructor|autodetect"/>
```
使用注解來實現自動裝配的示例如下:
@Component
public class BeanA {
? ? @Autowired
? ? private BeanB beanB;
? ? // Getter and Setter
}
通過配置自動裝配方式,Spring容器能夠根據預定義的規則來自動解決Bean之間的依賴關系,簡化了配置工作。開發人員可以根據實際情況選擇合適的自動裝配方式,提高了代碼的靈活性和可維護性。
spring是如何解決循環依賴的
Spring 在解決循環依賴時使用了三級緩存,分別是 singletonFactories、earlySingletonObjects 和 singletonObjects。這些緩存的使用可以幫助Spring在解決循環依賴問題時進行控制和管理。
-
singletonFactories:在單例模式下,當 Spring 創建 Bean 時,如果發現該 Bean 正在創建中,它會將這個創建中的 Bean 存儲在 singletonFactories 緩存中。這樣可以用來檢測循環依賴。
-
earlySingletonObjects:當 Bean 的實例化完成但尚未完成初始化時,該 Bean 會被存儲在 earlySingletonObjects 中。這樣可以確保其他 Bean 在初始化時可以引用到這些尚未初始化的 Bean。
-
singletonObjects:一旦 Bean 創建完成并完成初始化后,Spring 將會將其存儲在 singletonObjects 緩存中。這樣其他的 Bean 可以直接引用到已經初始化完成的 Bean 實例。
Spring 解決循環依賴的方法是通過依賴注入的過程中使用對象的代理。當發現循環依賴時,Spring 會創建一個提前暴露的、尚未完全初始化的代理對象作為依賴項,以滿足對象之間的交叉引用。
具體的解決流程如下:
-
當 Spring 容器初始化時,創建 Bean A 的過程中發現了循環依賴,需要解決 A 依賴于 B,而 B 又依賴于 A 的情況。
-
將正在創建 Bean A 的對象實例放入 singletonFactories 緩存中,表示該 Bean A 目前正在創建中。
-
接著創建 Bean B 的過程中,發現 B 依賴于 A,但 A 正在創建中,因此從 singletonFactories 緩存中獲取正在創建的 Bean A 的對象實例。
-
當 Bean A 創建完成但尚未完成初始化時,將其放入 earlySingletonObjects 緩存中,表示 Bean A 已經實例化但尚未初始化。
-
繼續創建 Bean B,并注入 Bean A 的未完成初始化的實例。
-
最后完成 Bean A 和 Bean B 的創建和初始化后,將 Bean A 和 Bean B 放入 singletonObjects 緩存中,表示它們是已經創建完成和初始化的 Bean 實例。
需要注意的是,雖然 Spring 能夠解決大多數情況下的循環依賴,但如果存在循環鏈,即 A 依賴于 B,B 依賴于 C,C 又依賴于 A,則 Spring 將無法解決這種循環依賴關系,會拋出 BeanCurrentlyInCreationException 異常。
總結一下,Spring 解決循環依賴的方式是通過提前暴露半初始化的代理對象,以滿足循環依賴關系中的引用,然后在完成所有 Bean 的創建和初始化后,將代理對象替換為實際對象。這樣就能夠成功解決循環依賴的問題。
不能解決的幾種循環依賴
-
構造函數循環依賴:如果Bean之間存在構造函數注入,且存在循環依賴,Spring容器無法解決這種循環依賴,會拋出BeanCurrentlyInCreationException異常。
-
原型Bean循環依賴:如果兩個原型Bean之間存在循環依賴,Spring容器無法解決這種循環依賴,因為原型Bean每次獲取都會創建新的對象實例,無法緩存起來,也無法通過代理對象解決。
-
@Async增強的bean循環依賴
pring中常見的幾種注解
Spring 框架中常見的注解包括但不限于:
-
@Component
:用于表示一個類是 Spring 容器管理的組件,通常與其他注解配合使用,如@Repository
、@Service
、@Controller
等。 -
@Autowired
:標記在字段、構造器、方法或者參數上,用于實現自動裝配,通過類型匹配進行依賴注入。 -
@Qualifier
:與@Autowired
配合使用,在存在多個具有相同類型的實例時,通過指定名稱來選擇具體的實例進行注入。 -
@Value
:用于注入簡單屬性值,支持 SpEL 表達式,例如@Value("${app.title}")
。 -
@Configuration
:標記在配置類上,表示該類是 Spring 的配置類,會告訴 Spring 應用上下文去加載 Bean 定義。 -
@Bean
:標記在方法上,將方法的返回對象注冊為一個 Bean,該對象會被 Spring IoC 容器管理。 -
@ComponentScan
:配置包掃描路徑,用于自動掃描并注冊標記有@Component
的類作為 Spring Bean。 -
@RequestMapping
:定義請求 URL 映射,用于處理 Web 請求,通常用在 Controller 類的方法上。 -
@Service
、@Repository
、@Controller
:用于添加更多細分類型的組件注解,讓 Spring 在掃描注解時能更清楚地區分各種組件類型。 -
@Scope
:定義 Bean 的作用域,例如 Singleton、Prototype、Request、Session 等。 -
@Aspect
、@Pointcut
、@Before
、@After
、@Around
、@AfterReturning
、@AfterThrowing
:用于定義切面和通知的注解,實現面向切面編程(AOP)。 -
@Transactional
:用于聲明事務處理的方法或類,標注在方法或類上,指明該方法或類需要進行事務處理。
這些注解是 Spring 框架中常見且重要的注解,它們能夠幫助我們簡化配置、實現依賴注入、定義 Bean、處理 Web 請求、實現事務管理等。
當然,還有更多在 Spring 框架中常見和常用的注解:
-
@RequestMapping
:在控制器類或方法上使用,用于映射 Web 請求的 URL 路徑和處理方法。 -
@PathVariable
:在方法參數上使用,用于從請求的 URL 中獲取路徑變量的值。 -
@RequestParam
:在方法參數上使用,用于從請求的參數中獲取值。 -
@RequestHeader
:在方法參數上使用,用于從請求頭中獲取值。 -
@ResponseBody
:通常在控制器方法上使用,用于將方法返回的對象轉換為指定的響應格式(如 JSON)并作為響應返回。 -
@ModelAttribute
:用于綁定請求參數到方法參數或方法的返回對象。 -
@Valid
:通常結合 JSR-303 標準的驗證注解一起使用,用于驗證方法參數或方法返回對象的數據的合法性。 -
@InitBinder
:用于配置用于表單數據綁定的 WebDataBinder,通常用于注冊自定義的屬性編輯器或驗證器。 -
@RestController
:一個方便的組合注解,結合了@Controller
和@ResponseBody
,用于定義 RESTful 風格的控制器。 -
@ConfigurationProperties
:用于將屬性綁定到配置類中的屬性上,可以用于統一管理項目的配置參數。 -
@Async
:標記在方法上,允許方法異步執行,可以提升系統的性能和并發處理能力。 -
@Enable*
系列注解:如@EnableCaching
、@EnableScheduling
、@EnableAsync
等,用于啟用相應的特性或功能。
這些注解在不同的場景中扮演著重要的角色,讓我們能夠更便捷地進行開發和配置,減少了大量的樣板代碼和配置工作。它們為 Spring 提供了更強大的功能和靈活性,簡化了開發過程。
spring、springmvc、springboot的區別是什么?
spring和springMvc:
-
spring是一個一站式的輕量級的java開發框架,核心是控制反轉(IOC)和面向切面(AOP),針對于開發的WEB層(springMvc)、業務層(Ioc)、持久層(jdbcTemplate)等都提供了多種配置解決方案;
-
springMvc是spring基礎之上的一個MVC框架,主要處理web開發的路徑映射和視圖渲染,屬于spring框架中WEB層開發的一部分;
springMvc和springBoot:
1、springMvc屬于一個企業WEB開發的MVC框架,涵蓋面包括前端視圖開發、文件配置、后臺接口邏輯開發等,XML、config等配置相對比較繁瑣復雜;
2、springBoot框架相對于springMvc框架來說,更專注于開發微服務后臺接口,不開發前端視圖,同時遵循默認優于配置,簡化了插件配置流程,不需要配置xml,相對springmvc,大大簡化了配置流程;
總結:
1、Spring 框架就像一個家族,有眾多衍生產品例如 boot、security、jpa等等。但他們的基礎都是Spring的ioc、aop等. ioc 提供了依賴注入的容器, aop解決了面向橫切面編程,然后在此兩者的基礎上實現了其他延伸產品的高級功能;
2、springMvc主要解決WEB開發的問題,是基于Servlet 的一個MVC框架,通過XML配置,統一開發前端視圖和后端邏輯;
3、由于Spring的配置非常復雜,各種XML、JavaConfig、servlet處理起來比較繁瑣,為了簡化開發者的使用,從而創造性地推出了springBoot框架,默認優于配置,簡化了springMvc的配置流程;但區別于springMvc的是,springBoot專注于單體微服務接口開發,和前端解耦,雖然springBoot也可以做成springMvc前后臺一起開發,但是這就有點不符合springBoot框架的初衷了;
springmvc工作流程是什么?
當發起請求時被前置的控制器攔截到請求,根據請求參數生成代理請求,找到請求對應的實際控制器,控制器處理請求,創建數據模型,訪問數據庫,將模型響應給中心控制器,控制器使用模型與視圖渲染視圖結果,將結果返回給中心控制器,再將結果返回給請求者。
1、DispatcherServlet表示前置控制器,是整個SpringMVC的控制中心。用戶發出請求,DispatcherServlet接收請求并攔截請求。
2、HandlerMapping為處理器映射。DispatcherServlet調用HandlerMapping,HandlerMapping根據請求url查找Handler。
3、返回處理器執行鏈,根據url查找控制器,并且將解析后的信息傳遞給DispatcherServlet
4、HandlerAdapter表示處理器適配器,其按照特定的規則去執行Handler。
5、執行handler找到具體的處理器
6、Controller將具體的執行信息返回給HandlerAdapter,如ModelAndView。
7、HandlerAdapter將視圖邏輯名或模型傳遞給DispatcherServlet。
8、DispatcherServlet調用視圖解析器(ViewResolver)來解析HandlerAdapter傳遞的邏輯視圖名。 9、視圖解析器將解析的邏輯視圖名傳給DispatcherServlet。
10、DispatcherServlet根據視圖解析器解析的視圖結果,調用具體的視圖,進行試圖渲染
11、將響應數據返回給客戶端
springmvc的九大組件有哪些?
Spring MVC(Model-View-Controller)是一個基于Java的MVC框架,用于開發Web應用程序。下面是Spring MVC的九大組件:
-
DispatcherServlet(調度器):是Spring MVC的核心組件,接收客戶端的請求并將其分派給相應的處理器。
-
HandlerMapping(處理器映射器):負責根據請求的URL映射到相應的處理器(Controller)。
-
HandlerAdapter(處理器適配器):將處理器(Controller)適配為一個能夠處理請求的處理器對象,并調用其處理方法。
-
HandlerInterceptor(處理器攔截器):對請求進行預處理和后處理。在請求被調度到處理器之前和之后,可以執行一些公共的任務,如身份驗證、日志記錄等。
-
ViewResolver(視圖解析器):根據邏輯視圖名(View Name)解析視圖對象,可以是JSP、Thymeleaf、Freemarker等等。
-
View(視圖):負責渲染模型數據,并將其呈現給用戶。常見的視圖技術包括JSP、HTML、JSON等。
-
ModelAndView(模型和視圖):將模型數據與視圖對象封裝在一起,以便向視圖傳遞數據并指示要呈現的視圖。
-
HandlerExceptionResolver(異常解析器):處理請求過程中產生的異常。將異常轉換為統一的錯誤視圖或錯誤消息。
-
MultipartResolver(多部分解析器):處理文件上傳請求,解析多部分請求,獲取上傳的文件和表單數據。
這些組件共同協作,使得Spring MVC能夠接收、處理和響應客戶端的請求,并以MVC模式將應用程序的邏輯、數據和視圖進行了清晰的分離。
Spring框架中有哪些不同類型的事件
Spring 提供了以下5種標準的事件:
上下文更新事件(ContextRefreshedEvent):在調用ConfigurableApplicationContext 接口中的refresh()方法時被觸發。
上下文開始事件(ContextStartedEvent):當容器調用ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發該事件。
上下文停止事件(ContextStoppedEvent):當容器調用ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件。
上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷毀。
請求處理事件(RequestHandledEvent):在Web應用中,當一個http請求(request)結束觸發該事件。如果一個bean實現了ApplicationListener接口,當一個ApplicationEvent 被發布以后,bean會自動被通知。