SpringBootApplication启动排除DataSourceAutoConfiguration不生效???
项目引用了新版本mybatis-spring-boot-starter之后启动不起来,报错Cannot determine embedded database driver class for database type NONE,在网上搜索是需要在排除掉spring自身的org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration这个类就可以,不让其自动配置。
由于项目是采用spring boot框架,所以在@SpringBootApplication中exclude这个类即可:
改之前代码:
1
2
3
4
5
6
7
8
9
10
@EnableAutoConfiguration
@SpringBootApplication
@EnableDubbo(multipleConfig = true)
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).profiles("default").build(args).run(args);
}
}
添加DataSourceAutoConfiguration排除之后:
1
2
3
4
5
6
7
8
9
10
@EnableAutoConfiguration
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableDubbo(multipleConfig = true)
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).profiles("default").build(args).run(args);
}
}
本以为这样就成功了,改之后发现重新启动项目还是报一样的错误,就比较奇怪,网上都是这样解决的,自己这里却不行。
现在只能猜测是不是我上面这样配置没生效,根本没有排除掉DataSourceAutoConfiguration呢,然后去debug了下spring这块源码,看spring是如何找到启动注解上要排除的类的。
最终找到了这个类AnnotatedElementUtils#searchWithGetSemanticsInAnnotations方法,该方法是查找该类上某个注解的定义配置的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
* This method is invoked by {@link #searchWithGetSemantics} to perform
* the actual search within the supplied list of annotations.
* <p>This method should be invoked first with locally declared annotations
* and then subsequently with inherited annotations, thereby allowing
* local annotations to take precedence over inherited annotations.
* <p>The {@code metaDepth} parameter is explained in the
* {@link Processor#process process()} method of the {@link Processor} API.
* @param element the element that is annotated with the supplied
* annotations, used for contextual logging; may be {@code null} if unknown
* @param annotations the annotations to search in
* @param annotationType the annotation type to find
* @param annotationName the fully qualified class name of the annotation
* type to find (as an alternative to {@code annotationType})
* @param containerType the type of the container that holds repeatable
* annotations, or {@code null} if the annotation is not repeatable
* @param processor the processor to delegate to
* @param visited the set of annotated elements that have already been visited
* @param metaDepth the meta-depth of the annotation
* @return the result of the processor (potentially {@code null})
* @since 4.2
*/
private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement element,
List<Annotation> annotations, Class<? extends Annotation> annotationType,
String annotationName, Class<? extends Annotation> containerType,
Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
// Search in annotations
// 这个for循环是在类上直接定义的注解上进行查找指定的注解
for (Annotation annotation : annotations) {
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
if (currentAnnotationType == annotationType ||
currentAnnotationType.getName().equals(annotationName) ||
processor.alwaysProcesses()) {
T result = processor.process(element, annotation, metaDepth);
if (result != null) {
if (processor.aggregates() && metaDepth == 0) {
processor.getAggregatedResults().add(result);
}
else {
return result;
}
}
}
// Repeatable annotations in container?
else if (currentAnnotationType == containerType) {
for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) {
T result = processor.process(element, contained, metaDepth);
if (result != null) {
// No need to post-process since repeatable annotations within a
// container cannot be composed annotations.
processor.getAggregatedResults().add(result);
}
}
}
}
}
// Recursively search in meta-annotations
// 如果根据类上直接定义的注解去找不到话,然后在遍历每一个注解,找寻其通过继承关系得到的注解
for (Annotation annotation : annotations) {
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
T result = searchWithGetSemantics(currentAnnotationType, annotationType,
annotationName, containerType, processor, visited, metaDepth + 1);
if (result != null) {
processor.postProcess(element, annotation, result);
if (processor.aggregates() && metaDepth == 0) {
processor.getAggregatedResults().add(result);
}
else {
return result;
}
}
}
}
return null;
}
拿我上面项目例子来说明,上面的代码我配置了@EnableAutoConfiguration和@SpringBootApplication两个注解,@SpringBootApplication里的exclude实际上使用的是@EnableAutoConfiguration里的exclude,所以当spring查找EnableAutoConfiguration这个注解的配置时候,根据上面spring代码可以知道,如果本地配置了,会优先取本地配置的,如果本地没有配置,才会通过第二个for循环,也就是从@SpringBootApplication里面去取,然后我项目代码也配置了@EnableAutoConfiguration,所以优先取本地配置,即在@SpringBootApplication配置的不会生效。
知道了这个结论之后,项目正常启动,改动就很简单了:
1
2
3
4
5
6
7
8
9
10
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
@SpringBootApplication
@EnableDubbo(multipleConfig = true)
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).profiles("default").build(args).run(args);
}
}
或者:(推荐使用这种方式)
1
2
3
4
5
6
7
8
9
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableDubbo(multipleConfig = true)
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).profiles("default").build(args).run(args);
}
}
总结
– 通过查看上面spring代码方法注释也能得到结论,这个方法应该首先调用本地声明的注释然后用继承的注释,从而允许本地注解优先于继承的注解。
– @SpringBootApplication是多个注解的组合,其中就已经包含了@EnableAutoConfiguration注解,所以引用了@SpringBootApplication注解之后不需要在手动注解@EnableAutoConfiguration