最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot利用dag加速Spring beans初始化的方法示例

 更新時(shí)間:2024年12月27日 10:56:27   作者:HBLOG  
本文介紹了利用DAG加速SpringBoot中Spring beans初始化,先解釋了DAG 概念及特性,包括節(jié)點(diǎn)入度出度、拓?fù)渑判虻?接著闡述加速Spring Bean初始化的實(shí)現(xiàn)思路,如識(shí)別依賴關(guān)系構(gòu)建DAG、拓?fù)渑判颉⒉⑿谐跏蓟疊ean及與Spring集成,還展示了相關(guān)代碼工程、測(cè)試結(jié)果及引用

1.什么是Dag?

有向無(wú)環(huán)圖(Directed Acyclic Graph),簡(jiǎn)稱DAG,是一種有向圖,其中沒(méi)有從節(jié)點(diǎn)出發(fā)經(jīng)過(guò)若干條邊后再回到該節(jié)點(diǎn)的路徑。換句話說(shuō),DAG中不存在環(huán)路。這種數(shù)據(jù)結(jié)構(gòu)常用于表示并解決具有依賴關(guān)系的問(wèn)題。

DAG的特性

  • 首先,DAG中的節(jié)點(diǎn)可以有入度和出度。節(jié)點(diǎn)的入度是指指向該節(jié)點(diǎn)的邊的數(shù)量,而節(jié)點(diǎn)的出度是指由該節(jié)點(diǎn)指向其他節(jié)點(diǎn)的邊的數(shù)量。在DAG中,節(jié)點(diǎn)的入度可以是0或正整數(shù),而出度可以是0或正整數(shù),但不能同時(shí)為負(fù)數(shù)。
  • DAG的另一個(gè)重要性質(zhì)是存在一個(gè)或多個(gè)拓?fù)渑判颉M負(fù)渑判蚴荄AG中節(jié)點(diǎn)的線性排列,滿足任意一條有向邊的起點(diǎn)在排序中都位于終點(diǎn)之前??梢允褂蒙疃葍?yōu)先搜索(DFS)或?qū)挾葍?yōu)先搜索(BFS)算法來(lái)生成拓?fù)渑判颉?/li>

DAG的應(yīng)用

  • 任務(wù)調(diào)度
  • 編譯器優(yōu)化
  • 數(shù)據(jù)流分析
  • 電路設(shè)計(jì)

2.如何加速Spring Bean初始化?

在Spring框架中進(jìn)行DAG(有向無(wú)環(huán)圖)分析以實(shí)現(xiàn)并行初始化,可以有效提升應(yīng)用程序啟動(dòng)的性能。通常情況下,Spring應(yīng)用程序的Bean是按依賴順序初始化的,而通過(guò)DAG分析可以識(shí)別出哪些Bean之間沒(méi)有依賴關(guān)系,并行初始化這些Bean可以減少啟動(dòng)時(shí)間。以下是實(shí)現(xiàn)思路:

1. 識(shí)別依賴關(guān)系,構(gòu)建DAG

首先需要識(shí)別Spring Bean之間的依賴關(guān)系。可以通過(guò)@DependsOn注解、構(gòu)造器注入或@Autowired等方式獲取Bean依賴。具體步驟:

  • 遍歷Spring上下文中的所有Bean定義。
  • 根據(jù)Bean的依賴關(guān)系構(gòu)建DAG,節(jié)點(diǎn)代表Bean,邊表示依賴關(guān)系。

Spring的ApplicationContext提供了getBeanDefinitionNames()方法可以列出所有的Bean,通過(guò)BeanDefinition可以分析出依賴。

2. 拓?fù)渑判?/h3>

通過(guò)拓?fù)渑判颍═opological Sorting)對(duì)DAG進(jìn)行排序,以確保Bean按依賴順序初始化。拓?fù)渑判蚩梢源_定哪些Bean可以并行初始化,哪些Bean必須在某些Bean之后初始化。 使用算法如Kahn’s Algorithm或DFS找到所有沒(méi)有依賴的Bean(入度為0的節(jié)點(diǎn)),這些節(jié)點(diǎn)可以并行初始化。

3. 并行初始化Bean

在完成拓?fù)渑判蚝?,使用多線程來(lái)并行初始化可以同時(shí)啟動(dòng)的Bean??梢允褂肑ava的ExecutorService或類似的線程池機(jī)制來(lái)管理并發(fā)的Bean初始化過(guò)程。 步驟:

  • 針對(duì)所有入度為0的節(jié)點(diǎn),啟動(dòng)一個(gè)線程來(lái)初始化它們。
  • 當(dāng)某個(gè)Bean初始化完成后,減少它所依賴的其他Bean的入度值。
  • 當(dāng)某個(gè)Bean的入度為0時(shí),可以在另一個(gè)線程中啟動(dòng)它的初始化。

4. Spring Integration

可以通過(guò)BeanFactoryPostProcessorApplicationContextInitializer來(lái)掛鉤到Spring的初始化流程中,分析Bean之間的依賴關(guān)系,并將并行化初始化邏輯集成到Spring容器的啟動(dòng)過(guò)程中。 具體方法:

  • 實(shí)現(xiàn)BeanFactoryPostProcessor,在Bean初始化之前分析Bean的依賴并構(gòu)建DAG。
  • 在Bean初始化階段,使用多線程并行處理獨(dú)立的Bean。

3.代碼工程

整體的依賴關(guān)系如下:

實(shí)驗(yàn)?zāi)繕?biāo)

實(shí)現(xiàn)自定義Bean并行化加載

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>dag</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jgrapht</groupId>
            <artifactId>jgrapht-core</artifactId>
            <version>1.5.1</version>
        </dependency>

    </dependencies>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <fork>true</fork>
                        <failOnError>false</failOnError>
                    </configuration>
                </plugin>

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.2</version>
                    <configuration>
                        <forkCount>0</forkCount>
                        <failIfNoTests>false</failIfNoTests>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

Bean初始化

package com.et.config;

import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.DirectedAcyclicGraph;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@Component
public class DAGBeanInitializer implements BeanFactoryPostProcessor {

    private final ExecutorService executorService = Executors.newFixedThreadPool(10);

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
        for (String beanName : beanFactory.getBeanDefinitionNames()) {
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
            beanDefinitionMap.put(beanName, beanDefinition);
        }

        // build DAG
        DirectedAcyclicGraph<String, DefaultEdge> dag = buildDAG(beanDefinitionMap,beanFactory);

        // bean layers
        List<Set<String>> layers = getBeansByLayer(dag);
        System.out.println("layers:"+layers);
        // init bean by layers
        initializeBeansInLayers(layers, beanFactory);
    }

    // DAG Bean
    private DirectedAcyclicGraph<String, DefaultEdge> buildDAG(Map<String, BeanDefinition> beanDefinitionMap, ConfigurableListableBeanFactory beanFactory) {
        DependencyResolver resolver = new DependencyResolver(beanFactory);
        DirectedAcyclicGraph<String, DefaultEdge> dag = new DirectedAcyclicGraph<>(DefaultEdge.class);
        for (String beanName : beanDefinitionMap.keySet()) {
            if(shouldLoadBean(beanName)) {
                dag.addVertex(beanName);
                String[] dependencies = beanDefinitionMap.get(beanName).getDependsOn();
                if (dependencies != null) {
                    for (String dependency : dependencies) {
                        dag.addEdge(dependency, beanName); 
                    }
                }
                // get @Autowired dependencies
                Set<String> autowireDependencies = resolver.getAllDependencies(beanName);
                for (String autowireDependency : autowireDependencies) {
                    // convert beanName
                    String autowireBeanName = convertToBeanName(autowireDependency);
                    dag.addVertex(autowireBeanName);
                    dag.addEdge(autowireBeanName, beanName);
                }
            }
        }
        return dag;
    }
    private String convertToBeanName(String className) {
        String simpleName = className.substring(className.lastIndexOf('.') + 1);
        return Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
    }
    private List<Set<String>> getBeansByLayer(DirectedAcyclicGraph<String,DefaultEdge> dag) {
        List<Set<String>> layers = new ArrayList<>();
        Map<String, Integer> inDegree = new HashMap<>();
        Queue<String> queue = new LinkedList<>();

        // init all nodes degree
        for (String vertex : dag) {
            int degree = dag.inDegreeOf(vertex);
            inDegree.put(vertex, degree);
            if (degree == 0) {
                queue.offer(vertex);  //zero degree as the first layer
            }
        }

        // BFS process everyLayers
        while (!queue.isEmpty()) {
            Set<String> currentLayer = new HashSet<>();
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                String currentBean = queue.poll();
                currentLayer.add(currentBean);

                // iterator layers
                for (String successor : getSuccessors(dag,currentBean)) {
                    inDegree.put(successor, inDegree.get(successor) - 1);
                    if (inDegree.get(successor) == 0) {
                        queue.offer(successor);  // add next layer when the degress is zero
                    }
                }
            }
            layers.add(currentLayer);
        }

        return layers;
    }
    // get next node
    private Set<String> getSuccessors(DirectedAcyclicGraph<String, DefaultEdge> dag, String vertex) {
        // get outgoingEdges
        Set<DefaultEdge> outgoingEdges = dag.outgoingEdgesOf(vertex);

        // find the next node
        return outgoingEdges.stream()
                .map(edge -> dag.getEdgeTarget(edge))
                .collect(Collectors.toSet());
    }
    // init beans by layer
    private void initializeBeansInLayers(List<Set<String>> layers, ConfigurableListableBeanFactory beanFactory) {
        for (Set<String> layer : layers) {
            // Beans of the same layer can be initialized in parallel
            List<CompletableFuture<Void>> futures = new ArrayList<>();
            for (String beanName : layer) {
                // only load beans that  wrote by yourself
                if (shouldLoadBean(beanName)) {
                    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                        try {
                            beanFactory.getBean(beanName);  // init Bean
                        } catch (Exception e) {
                            System.err.println("Failed to initialize bean: " + beanName);
                            e.printStackTrace();
                        }
                    }, executorService);
                    futures.add(future);
                }
            }
            //Wait for all beans in the current layer to be initialized before initializing the next layer.
            CompletableFuture<Void> allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
            allOf.join();  // make sure to be done on current layer
        }
    }

    private boolean shouldLoadBean(String beanName) {
        return beanName.startsWith("helloWorldController")
                ||beanName.startsWith("serviceOne")
                ||beanName.startsWith("serviceTwo")
                ||beanName.startsWith("serviceThree");
    }
}

獲取bean@Autowired依賴

package com.et.config;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;

@Component
public class DependencyResolver {

    private final ConfigurableListableBeanFactory beanFactory;

    @Autowired
    public DependencyResolver(ConfigurableListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    public Set<String> getAllDependencies(String beanName) {
        Set<String> dependencies = new HashSet<>();

        // get Bean definite
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);

        // reflect
        try {
            Class<?> beanClass = Class.forName(beanDefinition.getBeanClassName());
            Field[] fields = beanClass.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    dependencies.add(field.getType().getName()); 
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        return dependencies;
    }
}

controller

package com.et.controller;

import com.et.service.ServiceTwo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.et.service.*;
import java.util.HashMap;
import java.util.Map;

@RestController
public class HelloWorldController {
    @Autowired
    ServiceOne ServiceOne;
    @Autowired
    ServiceTwo ServiceTwo;
    @RequestMapping("/hello")
    public Map<String, Object> showHelloWorld(){
        Map<String, Object> map = new HashMap<>();
        map.put("msg", "HelloWorld");
        return map;
    }
}

service

package com.et.service;

import org.springframework.stereotype.Service;

/**
 * @author liuhaihua
 * @version 1.0
 * @ClassName ServiceOne
 * @Description todo
 * @date 2024/09/20/ 14:01
 */
@Service
public class ServiceOne {
    private   void  sayhi(){
        System.out.println("this is service one sayhi");
    }
}

package com.et.service;

import org.springframework.stereotype.Service;

/**
 * @author liuhaihua
 * @version 1.0
 * @ClassName ServiceOne
 * @Description todo
 * @date 2024/09/20/ 14:01
 */
@Service
public class ServiceThree {

    private   void  sayhi(){
        System.out.println("this is service three sayhi");
    }
}

package com.et.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author liuhaihua
 * @version 1.0
 * @ClassName ServiceOne
 * @Description todo
 * @date 2024/09/20/ 14:01
 */
@Service
public class ServiceTwo {
    @Autowired
    ServiceThree serviceThree;
    private   void  sayhi(){
        System.out.println("this is service two sayhi");
    }
}

只是一些關(guān)鍵代碼

4.測(cè)試

啟動(dòng)Spring Boot工程,查看bean加載順序如下

2024-09-20T15:51:27.081+08:00 INFO 33188 --- [ main] com.et.DemoApplication : Starting DemoApplication using Java 17.0.9 with PID 33188 (D:\IdeaProjects\ETFramework\dag\target\classes started by Dell in D:\IdeaProjects\ETFramework)
2024-09-20T15:51:27.085+08:00 INFO 33188 --- [ main] com.et.DemoApplication : No active profile set, falling back to 1 default profile: "default"
layers:[[serviceOne, serviceThree], [serviceTwo], [helloWorldController]]
2024-09-20T15:51:28.286+08:00 INFO 33188 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8088 (http)
2024-09-20T15:51:28.297+08:00 INFO 33188 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2024-09-20T15:51:28.297+08:00 INFO 33188 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.17]
2024-09-20T15:51:28.373+08:00 INFO 33188 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2024-09-20T15:51:28.374+08:00 INFO 33188 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1198 ms
2024-09-20T15:51:28.725+08:00 INFO 33188 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8088 (http) with context path ''
2024-09-20T15:51:28.732+08:00 INFO 33188 --- [ main] com.et.DemoApplication

以上就是SpringBoot利用dag加速Spring beans初始化的方法示例的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot dag加速beans初始化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • servlet 解決亂碼問(wèn)題

    servlet 解決亂碼問(wèn)題

    這篇文章主要介紹了servlet 解決亂碼問(wèn)題 ,需要的朋友可以參考下
    2015-04-04
  • Java中JWT雙簽發(fā)認(rèn)證過(guò)程的實(shí)現(xiàn)

    Java中JWT雙簽發(fā)認(rèn)證過(guò)程的實(shí)現(xiàn)

    在Java項(xiàng)目中實(shí)現(xiàn)JWT雙簽發(fā)認(rèn)證(即同時(shí)生成Access Token和Refresh Token),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-08-08
  • spring boot 自定義starter的實(shí)現(xiàn)教程

    spring boot 自定義starter的實(shí)現(xiàn)教程

    下面小編就為大家分享一篇spring boot 自定義starter的實(shí)現(xiàn)教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • Java  Object類中的常用API介紹

    Java  Object類中的常用API介紹

    這篇文章主要介紹了Java  Object類中的常用API介紹,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-11-11
  • 基于Mybatis的配置文件入門(mén)必看篇

    基于Mybatis的配置文件入門(mén)必看篇

    這篇文章主要介紹了Mybatis的配置文件入門(mén),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java代碼實(shí)現(xiàn)矩形覆蓋實(shí)例

    Java代碼實(shí)現(xiàn)矩形覆蓋實(shí)例

    這篇文章主要介紹了Java代碼實(shí)現(xiàn)矩形覆蓋實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下
    2019-06-06
  • spring事務(wù)之事務(wù)掛起和事務(wù)恢復(fù)源碼解讀

    spring事務(wù)之事務(wù)掛起和事務(wù)恢復(fù)源碼解讀

    這篇文章主要介紹了spring事務(wù)之事務(wù)掛起和事務(wù)恢復(fù)源碼解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • spring cloud 使用Zuul 實(shí)現(xiàn)API網(wǎng)關(guān)服務(wù)問(wèn)題

    spring cloud 使用Zuul 實(shí)現(xiàn)API網(wǎng)關(guān)服務(wù)問(wèn)題

    這篇文章主要介紹了spring cloud 使用Zuul 實(shí)現(xiàn)API網(wǎng)關(guān)服務(wù)問(wèn)題,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-05-05
  • JavaWeb之Filter過(guò)濾器詳解

    JavaWeb之Filter過(guò)濾器詳解

    本篇文章主要介紹了JavaWeb之Filter過(guò)濾器詳解,實(shí)例分析了JavaWeb之Filter過(guò)濾器的使用技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。
    2017-03-03
  • Java中集合遍歷的方法示例代碼展示

    Java中集合遍歷的方法示例代碼展示

    在 Java 編程中,集合(Collection)是用于存儲(chǔ)和操作一組對(duì)象的重要工具,無(wú)論是數(shù)組、列表(List)、集合(Set),還是映射(Map),它們都提供了在不同場(chǎng)景下靈活使用的數(shù)據(jù)結(jié)構(gòu),這篇文章主要介紹了Java中集合遍歷的方法示例代碼展示,需要的朋友可以參考下
    2024-08-08

最新評(píng)論

西藏| 临猗县| 滕州市| 罗甸县| 乌拉特后旗| 绥棱县| 南溪县| 夹江县| 类乌齐县| 阜新市| 富裕县| 科技| 清水河县| 深水埗区| 澎湖县| 留坝县| 南充市| 德清县| 溧水县| 东光县| 施甸县| 南靖县| 朝阳县| 梁平县| 黑龙江省| 宁河县| 永兴县| 襄垣县| 合江县| 四子王旗| 民县| 甘孜| 巴彦县| 象山县| 云阳县| 潞西市| 广平县| 阳曲县| 南雄市| 湘潭市| 青川县|