66import io .github .lvyahui8 .spring .aggregate .interceptor .AggregateQueryInterceptor ;
77import io .github .lvyahui8 .spring .aggregate .interceptor .AggregateQueryInterceptorChain ;
88import io .github .lvyahui8 .spring .aggregate .interceptor .impl .AggregateQueryInterceptorChainImpl ;
9+ import io .github .lvyahui8 .spring .aggregate .model .DataConsumeDefinition ;
910import io .github .lvyahui8 .spring .aggregate .model .DataProvideDefinition ;
1011import io .github .lvyahui8 .spring .aggregate .repository .DataProviderRepository ;
1112import io .github .lvyahui8 .spring .aggregate .repository .impl .DataProviderRepositoryImpl ;
1415import io .github .lvyahui8 .spring .aggregate .util .DefinitionUtils ;
1516import io .github .lvyahui8 .spring .annotation .DataProvider ;
1617import lombok .extern .slf4j .Slf4j ;
18+ import org .apache .commons .lang3 .StringUtils ;
1719import org .reflections .Reflections ;
1820import org .reflections .scanners .MethodAnnotationsScanner ;
1921import org .springframework .beans .BeansException ;
3032import org .springframework .core .annotation .Order ;
3133import org .springframework .scheduling .concurrent .CustomizableThreadFactory ;
3234import org .springframework .util .Assert ;
33- import org .springframework .util .StringUtils ;
3435
3536import java .lang .reflect .Method ;
3637import java .lang .reflect .Modifier ;
3940import java .util .concurrent .LinkedBlockingDeque ;
4041import java .util .concurrent .ThreadPoolExecutor ;
4142import java .util .concurrent .TimeUnit ;
43+ import java .util .stream .Collectors ;
4244
4345/**
4446 * @author lvyahui (lvyahui8@gmail.com,lvyahui8@126.com)
@@ -65,11 +67,44 @@ public DataBeanAggregateQueryFacade dataBeanAggregateQueryFacade(
6567 return new DataBeanAggregateQueryFacadeImpl (dataBeanAggregateQueryService (dataProviderRepository ));
6668 }
6769
70+ private void checkCycle (Map <String ,Set <String >> graphAdjMap ) {
71+ Map <String ,Integer > visitStatusMap = new HashMap <>(graphAdjMap .size () * 2 );
72+ Stack <String > stack = new Stack <>();
73+ for (Map .Entry <String , Set <String >> item : graphAdjMap .entrySet ()) {
74+ if (visitStatusMap .containsKey (item .getKey ())) {
75+ continue ;
76+ }
77+ dfs (graphAdjMap ,visitStatusMap ,item .getKey ());
78+ }
79+ }
80+
81+ private void dfs (Map <String ,Set <String >> graphAdjMap ,Map <String ,Integer > visitStatusMap , String node ) {
82+ if (visitStatusMap .containsKey (node )) {
83+ if (visitStatusMap .get (node ) == 1 ) {
84+ List <String > relatedNodes = new ArrayList <>();
85+ for (Map .Entry <String ,Integer > item : visitStatusMap .entrySet ()) {
86+ if (item .getValue () == 1 ) {
87+ relatedNodes .add (item .getKey ());
88+ }
89+ }
90+ throw new IllegalStateException ("There are loops in the dependency graph. Related nodes:" + StringUtils .join (relatedNodes ));
91+ }
92+ return ;
93+ }
94+ visitStatusMap .put (node ,1 );
95+ log .info ("visited:{}" , node );
96+ for (String relateNode : graphAdjMap .get (node )) {
97+ dfs (graphAdjMap ,visitStatusMap ,relateNode );
98+ }
99+ visitStatusMap .put (node ,2 );
100+ }
101+
68102 @ Bean
69103 @ ConditionalOnMissingBean
70104 public DataBeanAggregateQueryService dataBeanAggregateQueryService (
71105 @ Qualifier ("dataProviderRepository" ) DataProviderRepository dataProviderRepository ) {
72106 if (properties .getBasePackages () != null ) {
107+ Map <String ,Set <String >> provideDependMap = new HashMap <>();
73108 for (String basePackage : properties .getBasePackages ()) {
74109 Reflections reflections = new Reflections (basePackage , new MethodAnnotationsScanner ());
75110 Set <Method > providerMethods = reflections .getMethodsAnnotatedWith (DataProvider .class );
@@ -80,13 +115,18 @@ public DataBeanAggregateQueryService dataBeanAggregateQueryService (
80115 Assert .isTrue (Modifier .isPublic (method .getModifiers ()),"data provider method must be public" );
81116 Assert .isTrue (! StringUtils .isEmpty (dataId ),"data id must be not null!" );
82117 DataProvideDefinition provider = DefinitionUtils .getProvideDefinition (method );
118+
83119 provider .setId (dataId );
84120 provider .setIdempotent (beanProvider .idempotent ());
85121 provider .setTimeout (beanProvider .timeout () > 0 ? beanProvider .timeout () : properties .getDefaultTimeout ());
122+ Assert .isTrue (! dataProviderRepository .contains (dataId ), "Data providers with the same name are not allowed. dataId: " + dataId );
123+ provideDependMap .put (dataId ,provider .getDepends ().stream ().map (DataConsumeDefinition ::getId ).collect (Collectors .toSet ()));
86124 dataProviderRepository .put (provider );
87125 }
88126 }
127+ checkCycle (provideDependMap );
89128 }
129+
90130 DataBeanAggregateQueryServiceImpl service = new DataBeanAggregateQueryServiceImpl ();
91131 RuntimeSettings runtimeSettings = new RuntimeSettings ();
92132 runtimeSettings .setEnableLogging (properties .getEnableLogging () != null
0 commit comments