20
20
import java .net .URL ;
21
21
import java .util .ArrayList ;
22
22
import java .util .Arrays ;
23
- import java .util .Collections ;
24
23
import java .util .Enumeration ;
25
24
import java .util .List ;
26
25
import java .util .Properties ;
27
26
28
27
import org .apache .commons .logging .Log ;
29
28
import org .apache .commons .logging .LogFactory ;
30
29
31
- import org .springframework .core .annotation . AnnotationAwareOrderComparator ;
30
+ import org .springframework .core .OrderComparator ;
32
31
import org .springframework .core .io .UrlResource ;
33
32
import org .springframework .util .Assert ;
34
33
import org .springframework .util .ClassUtils ;
35
34
import org .springframework .util .StringUtils ;
36
35
37
36
/**
38
- * General purpose factory loading mechanism.
37
+ * General purpose factory loading mechanism for internal use within the framework .
39
38
*
40
39
* <p>The {@code SpringFactoriesLoader} loads and instantiates factories of a given type
41
- * from a given file location. If a location is not given, the {@linkplain
42
- * #DEFAULT_FACTORIES_LOCATION default location} is used.
43
- *
44
- * <p>The file should be in {@link Properties} format, where the key is the fully
45
- * qualified interface or abstract class name, and the value is a comma separated list of
46
- * implementations. For instance:
40
+ * from "META-INF/spring.factories" files. The file should be in {@link Properties} format,
41
+ * where the key is the fully qualified interface or abstract class name, and the value
42
+ * is a comma-separated list of implementation class names. For instance:
47
43
*
48
44
* <pre class="code">example.MyService=example.MyServiceImpl1,example.MyServiceImpl2</pre>
49
45
*
50
46
* where {@code MyService} is the name of the interface, and {@code MyServiceImpl1} and
51
47
* {@code MyServiceImpl2} are the two implementations.
52
48
*
53
49
* @author Arjen Poutsma
50
+ * @author Juergen Hoeller
54
51
* @since 3.2
55
52
*/
56
53
public abstract class SpringFactoriesLoader {
57
54
58
- private static final Log logger = LogFactory .getLog (SpringFactoriesLoader .class );
59
-
60
55
/** The location to look for the factories. Can be present in multiple JAR files. */
61
- public static final String DEFAULT_FACTORIES_LOCATION = "META-INF/spring.factories" ;
56
+ private static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories" ;
57
+
58
+ private static final Log logger = LogFactory .getLog (SpringFactoriesLoader .class );
62
59
63
- /**
64
- * Loads the factory implementations of the given type from the default location.
65
- *
66
- * <p>The returned factories are ordered in accordance with the {@link
67
- * AnnotationAwareOrderComparator}.
68
- *
69
- * @param factoryClass the interface or abstract class representing the factory
70
- * @throws IllegalArgumentException in case of errors
71
- */
72
- public static <T > List <T > loadFactories (Class <T > factoryClass ) {
73
- return loadFactories (factoryClass , null , null );
74
- }
75
60
76
61
/**
77
62
* Loads the factory implementations of the given type from the default location, using
78
63
* the given class loader.
79
- *
80
- * <p>The returned factories are ordered in accordance with the {@link
81
- * AnnotationAwareOrderComparator}.
82
- *
83
- * @param factoryClass the interface or abstract class representing the factory
84
- * @param classLoader the ClassLoader to use for loading, can be {@code null} to use the
85
- * default
86
- * @throws IllegalArgumentException in case of errors
87
- */
88
- public static <T > List <T > loadFactories (Class <T > factoryClass ,
89
- ClassLoader classLoader ) {
90
- return loadFactories (factoryClass , classLoader , null );
91
- }
92
-
93
- /**
94
- * Loads the factory implementations of the given type from the given location, using the
95
- * given class loader.
96
- *
97
- * <p>The returned factories are ordered in accordance with the {@link
98
- * AnnotationAwareOrderComparator}.
99
- *
64
+ * <p>The returned factories are ordered in accordance with the {@link OrderComparator}.
100
65
* @param factoryClass the interface or abstract class representing the factory
101
- * @param classLoader the ClassLoader to use for loading, can be {@code null} to use the
102
- * default
103
- * @param factoriesLocation the factories file location, can be {@code null} to use the
104
- * {@linkplain #DEFAULT_FACTORIES_LOCATION default}
105
- * @throws IllegalArgumentException in case of errors
66
+ * @param classLoader the ClassLoader to use for loading (can be {@code null} to use the default)
106
67
*/
107
- public static <T > List <T > loadFactories (Class <T > factoryClass ,
108
- ClassLoader classLoader , String factoriesLocation ) {
68
+ public static <T > List <T > loadFactories (Class <T > factoryClass , ClassLoader classLoader ) {
109
69
Assert .notNull (factoryClass , "'factoryClass' must not be null" );
110
-
111
70
if (classLoader == null ) {
112
- classLoader = ClassUtils .getDefaultClassLoader ();
113
- }
114
- if (factoriesLocation == null ) {
115
- factoriesLocation = DEFAULT_FACTORIES_LOCATION ;
71
+ classLoader = SpringFactoriesLoader .class .getClassLoader ();
116
72
}
117
-
118
- List <String > factoryNames =
119
- loadFactoryNames (factoryClass , classLoader , factoriesLocation );
120
-
73
+ List <String > factoryNames = loadFactoryNames (factoryClass , classLoader );
121
74
if (logger .isTraceEnabled ()) {
122
- logger .trace (
123
- "Loaded [" + factoryClass .getName () + "] names: " + factoryNames );
75
+ logger .trace ("Loaded [" + factoryClass .getName () + "] names: " + factoryNames );
124
76
}
125
-
126
77
List <T > result = new ArrayList <T >(factoryNames .size ());
127
78
for (String factoryName : factoryNames ) {
128
79
result .add (instantiateFactory (factoryName , factoryClass , classLoader ));
129
80
}
130
-
131
- Collections .sort (result , new AnnotationAwareOrderComparator ());
132
-
81
+ OrderComparator .sort (result );
133
82
return result ;
134
83
}
135
84
136
- private static List <String > loadFactoryNames (Class <?> factoryClass ,
137
- ClassLoader classLoader , String factoriesLocation ) {
138
-
85
+ private static List <String > loadFactoryNames (Class <?> factoryClass , ClassLoader classLoader ) {
139
86
String factoryClassName = factoryClass .getName ();
140
-
141
87
try {
142
88
List <String > result = new ArrayList <String >();
143
- Enumeration <URL > urls = classLoader .getResources (factoriesLocation );
89
+ Enumeration <URL > urls = classLoader .getResources (FACTORIES_RESOURCE_LOCATION );
144
90
while (urls .hasMoreElements ()) {
145
91
URL url = urls .nextElement ();
146
- Properties properties =
147
- PropertiesLoaderUtils .loadProperties (new UrlResource (url ));
92
+ Properties properties = PropertiesLoaderUtils .loadProperties (new UrlResource (url ));
148
93
String factoryClassNames = properties .getProperty (factoryClassName );
149
- result .addAll (Arrays .asList (
150
- StringUtils .commaDelimitedListToStringArray (factoryClassNames )));
94
+ result .addAll (Arrays .asList (StringUtils .commaDelimitedListToStringArray (factoryClassNames )));
151
95
}
152
96
return result ;
153
97
}
154
98
catch (IOException ex ) {
155
- throw new IllegalArgumentException (
156
- "Unable to load [" + factoryClass .getName () +
157
- "] factories from location [" +
158
- factoriesLocation + "]" , ex );
99
+ throw new IllegalArgumentException ("Unable to load [" + factoryClass .getName () +
100
+ "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]" , ex );
159
101
}
160
-
161
-
162
102
}
163
103
164
104
@ SuppressWarnings ("unchecked" )
165
- private static <T > T instantiateFactory (String instanceClassName ,
166
- Class <T > factoryClass , ClassLoader classLoader ) {
105
+ private static <T > T instantiateFactory (String instanceClassName , Class <T > factoryClass , ClassLoader classLoader ) {
167
106
try {
168
107
Class <?> instanceClass = ClassUtils .forName (instanceClassName , classLoader );
169
108
if (!factoryClass .isAssignableFrom (instanceClass )) {
170
109
throw new IllegalArgumentException (
171
- "Class [" + instanceClassName + "] is not assignable to [" +
172
- factoryClass .getName () + "]" );
110
+ "Class [" + instanceClassName + "] is not assignable to [" + factoryClass .getName () + "]" );
173
111
}
174
112
return (T ) instanceClass .newInstance ();
175
113
}
176
- catch (ClassNotFoundException ex ) {
177
- throw new IllegalArgumentException (
178
- factoryClass .getName () + " class [" + instanceClassName +
179
- "] not found" , ex );
180
- }
181
- catch (LinkageError err ) {
182
- throw new IllegalArgumentException (
183
- "Invalid " + factoryClass .getName () + " class [" + instanceClassName +
184
- "]: problem with handler class file or dependent class" , err );
185
- }
186
- catch (InstantiationException ex ) {
187
- throw new IllegalArgumentException (
188
- "Could not instantiate bean class [" + instanceClassName +
189
- "]: Is it an abstract class?" , ex );
190
- }
191
- catch (IllegalAccessException ex ) {
192
- throw new IllegalArgumentException (
193
- "Could not instantiate bean class [" + instanceClassName +
194
- "Is the constructor accessible?" , ex );
114
+ catch (Throwable ex ) {
115
+ throw new IllegalArgumentException ("Cannot instantiate factory class: " + factoryClass .getName (), ex );
195
116
}
196
117
}
197
118
198
- }
119
+ }
0 commit comments