|
|
|
|
@ -16,6 +16,7 @@
@@ -16,6 +16,7 @@
|
|
|
|
|
|
|
|
|
|
package org.springframework.boot.autoconfigure.condition; |
|
|
|
|
|
|
|
|
|
import java.security.AccessControlException; |
|
|
|
|
import java.util.ArrayList; |
|
|
|
|
import java.util.Collection; |
|
|
|
|
import java.util.Collections; |
|
|
|
|
@ -90,53 +91,30 @@ class OnClassCondition extends SpringBootCondition
@@ -90,53 +91,30 @@ class OnClassCondition extends SpringBootCondition
|
|
|
|
|
// additional thread seems to offer the best performance. More threads make
|
|
|
|
|
// things worse
|
|
|
|
|
int split = autoConfigurationClasses.length / 2; |
|
|
|
|
GetOutcomesThread thread = new GetOutcomesThread(autoConfigurationClasses, 0, |
|
|
|
|
split, autoConfigurationMetadata); |
|
|
|
|
thread.start(); |
|
|
|
|
ConditionOutcome[] secondHalf = getOutcomes(autoConfigurationClasses, split, |
|
|
|
|
autoConfigurationClasses.length, autoConfigurationMetadata); |
|
|
|
|
try { |
|
|
|
|
thread.join(); |
|
|
|
|
} |
|
|
|
|
catch (InterruptedException ex) { |
|
|
|
|
Thread.currentThread().interrupt(); |
|
|
|
|
} |
|
|
|
|
ConditionOutcome[] firstHalf = thread.getResult(); |
|
|
|
|
OutcomesResolver firstHalfResolver = createOutcomesResolver( |
|
|
|
|
autoConfigurationClasses, 0, split, autoConfigurationMetadata); |
|
|
|
|
OutcomesResolver secondHalfResolver = new StandardOutcomesResolver( |
|
|
|
|
autoConfigurationClasses, split, autoConfigurationClasses.length, |
|
|
|
|
autoConfigurationMetadata, this.beanClassLoader); |
|
|
|
|
ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes(); |
|
|
|
|
ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes(); |
|
|
|
|
ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length]; |
|
|
|
|
System.arraycopy(firstHalf, 0, outcomes, 0, firstHalf.length); |
|
|
|
|
System.arraycopy(secondHalf, 0, outcomes, split, secondHalf.length); |
|
|
|
|
return outcomes; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private ConditionOutcome[] getOutcomes(final String[] autoConfigurationClasses, |
|
|
|
|
private OutcomesResolver createOutcomesResolver(String[] autoConfigurationClasses, |
|
|
|
|
int start, int end, AutoConfigurationMetadata autoConfigurationMetadata) { |
|
|
|
|
ConditionOutcome[] outcomes = new ConditionOutcome[end - start]; |
|
|
|
|
for (int i = start; i < end; i++) { |
|
|
|
|
String autoConfigurationClass = autoConfigurationClasses[i]; |
|
|
|
|
Set<String> candidates = autoConfigurationMetadata |
|
|
|
|
.getSet(autoConfigurationClass, "ConditionalOnClass"); |
|
|
|
|
if (candidates != null) { |
|
|
|
|
outcomes[i - start] = getOutcome(candidates); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return outcomes; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private ConditionOutcome getOutcome(Set<String> candidates) { |
|
|
|
|
OutcomesResolver outcomesResolver = new StandardOutcomesResolver( |
|
|
|
|
autoConfigurationClasses, start, end, autoConfigurationMetadata, |
|
|
|
|
this.beanClassLoader); |
|
|
|
|
try { |
|
|
|
|
List<String> missing = getMatches(candidates, MatchType.MISSING, |
|
|
|
|
this.beanClassLoader); |
|
|
|
|
if (!missing.isEmpty()) { |
|
|
|
|
return ConditionOutcome |
|
|
|
|
.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class) |
|
|
|
|
.didNotFind("required class", "required classes") |
|
|
|
|
.items(Style.QUOTE, missing)); |
|
|
|
|
} |
|
|
|
|
return new ThreadedOutcomesResolver(outcomesResolver); |
|
|
|
|
} |
|
|
|
|
catch (Exception ex) { |
|
|
|
|
// We'll get another chance later
|
|
|
|
|
catch (AccessControlException ex) { |
|
|
|
|
return outcomesResolver; |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
@ -262,7 +240,45 @@ class OnClassCondition extends SpringBootCondition
@@ -262,7 +240,45 @@ class OnClassCondition extends SpringBootCondition
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private class GetOutcomesThread extends Thread { |
|
|
|
|
private interface OutcomesResolver { |
|
|
|
|
|
|
|
|
|
ConditionOutcome[] resolveOutcomes(); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static final class ThreadedOutcomesResolver implements OutcomesResolver { |
|
|
|
|
|
|
|
|
|
private final Thread thread; |
|
|
|
|
|
|
|
|
|
private volatile ConditionOutcome[] outcomes; |
|
|
|
|
|
|
|
|
|
private ThreadedOutcomesResolver(final OutcomesResolver outcomesResolver) { |
|
|
|
|
this.thread = new Thread(new Runnable() { |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public void run() { |
|
|
|
|
ThreadedOutcomesResolver.this.outcomes = outcomesResolver |
|
|
|
|
.resolveOutcomes(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}); |
|
|
|
|
this.thread.start(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public ConditionOutcome[] resolveOutcomes() { |
|
|
|
|
try { |
|
|
|
|
this.thread.join(); |
|
|
|
|
} |
|
|
|
|
catch (InterruptedException ex) { |
|
|
|
|
Thread.currentThread().interrupt(); |
|
|
|
|
} |
|
|
|
|
return this.outcomes; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private final class StandardOutcomesResolver implements OutcomesResolver { |
|
|
|
|
|
|
|
|
|
private final String[] autoConfigurationClasses; |
|
|
|
|
|
|
|
|
|
@ -272,25 +288,55 @@ class OnClassCondition extends SpringBootCondition
@@ -272,25 +288,55 @@ class OnClassCondition extends SpringBootCondition
|
|
|
|
|
|
|
|
|
|
private final AutoConfigurationMetadata autoConfigurationMetadata; |
|
|
|
|
|
|
|
|
|
private ConditionOutcome[] outcomes; |
|
|
|
|
private final ClassLoader beanClassLoader; |
|
|
|
|
|
|
|
|
|
GetOutcomesThread(String[] autoConfigurationClasses, int start, int end, |
|
|
|
|
AutoConfigurationMetadata autoConfigurationMetadata) { |
|
|
|
|
private StandardOutcomesResolver(String[] autoConfigurationClasses, int start, |
|
|
|
|
int end, AutoConfigurationMetadata autoConfigurationMetadata, |
|
|
|
|
ClassLoader beanClassLoader) { |
|
|
|
|
this.autoConfigurationClasses = autoConfigurationClasses; |
|
|
|
|
this.start = start; |
|
|
|
|
this.end = end; |
|
|
|
|
this.autoConfigurationMetadata = autoConfigurationMetadata; |
|
|
|
|
this.beanClassLoader = beanClassLoader; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public void run() { |
|
|
|
|
this.outcomes = getOutcomes(this.autoConfigurationClasses, this.start, |
|
|
|
|
this.end, this.autoConfigurationMetadata); |
|
|
|
|
public ConditionOutcome[] resolveOutcomes() { |
|
|
|
|
return getOutcomes(this.autoConfigurationClasses, this.start, this.end, |
|
|
|
|
this.autoConfigurationMetadata); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public ConditionOutcome[] getResult() { |
|
|
|
|
return this.outcomes; |
|
|
|
|
private ConditionOutcome[] getOutcomes(final String[] autoConfigurationClasses, |
|
|
|
|
int start, int end, AutoConfigurationMetadata autoConfigurationMetadata) { |
|
|
|
|
ConditionOutcome[] outcomes = new ConditionOutcome[end - start]; |
|
|
|
|
for (int i = start; i < end; i++) { |
|
|
|
|
String autoConfigurationClass = autoConfigurationClasses[i]; |
|
|
|
|
Set<String> candidates = autoConfigurationMetadata |
|
|
|
|
.getSet(autoConfigurationClass, "ConditionalOnClass"); |
|
|
|
|
if (candidates != null) { |
|
|
|
|
outcomes[i - start] = getOutcome(candidates); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return outcomes; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private ConditionOutcome getOutcome(Set<String> candidates) { |
|
|
|
|
try { |
|
|
|
|
List<String> missing = getMatches(candidates, MatchType.MISSING, |
|
|
|
|
this.beanClassLoader); |
|
|
|
|
if (!missing.isEmpty()) { |
|
|
|
|
return ConditionOutcome.noMatch( |
|
|
|
|
ConditionMessage.forCondition(ConditionalOnClass.class) |
|
|
|
|
.didNotFind("required class", "required classes") |
|
|
|
|
.items(Style.QUOTE, missing)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
catch (Exception ex) { |
|
|
|
|
// We'll get another chance later
|
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|