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