1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.spring.mapper;
17
18 import static org.springframework.util.Assert.notNull;
19
20 import java.lang.annotation.Annotation;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Optional;
25 import java.util.regex.Pattern;
26
27 import org.apache.ibatis.session.SqlSessionFactory;
28 import org.mybatis.spring.SqlSessionTemplate;
29 import org.springframework.beans.BeanUtils;
30 import org.springframework.beans.PropertyValues;
31 import org.springframework.beans.factory.BeanNameAware;
32 import org.springframework.beans.factory.InitializingBean;
33 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
34 import org.springframework.beans.factory.config.PropertyResourceConfigurer;
35 import org.springframework.beans.factory.config.TypedStringValue;
36 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
37 import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
38 import org.springframework.beans.factory.support.BeanNameGenerator;
39 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
40 import org.springframework.context.ApplicationContext;
41 import org.springframework.context.ApplicationContextAware;
42 import org.springframework.context.ConfigurableApplicationContext;
43 import org.springframework.core.env.Environment;
44 import org.springframework.core.type.filter.AnnotationTypeFilter;
45 import org.springframework.core.type.filter.AspectJTypeFilter;
46 import org.springframework.core.type.filter.AssignableTypeFilter;
47 import org.springframework.core.type.filter.RegexPatternTypeFilter;
48 import org.springframework.core.type.filter.TypeFilter;
49 import org.springframework.lang.Nullable;
50 import org.springframework.util.ClassUtils;
51 import org.springframework.util.StringUtils;
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 public class MapperScannerConfigurer
101 implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
102
103 private String basePackage;
104
105 private boolean addToConfig = true;
106
107 private String lazyInitialization;
108
109 private SqlSessionFactory sqlSessionFactory;
110
111 private SqlSessionTemplate sqlSessionTemplate;
112
113 private String sqlSessionFactoryBeanName;
114
115 private String sqlSessionTemplateBeanName;
116
117 private Class<? extends Annotation> annotationClass;
118
119 private Class<?> markerInterface;
120
121 private List<TypeFilter> excludeFilters;
122
123 private List<Map<String, String>> rawExcludeFilters;
124
125 private Class<? extends MapperFactoryBean> mapperFactoryBeanClass;
126
127 private ApplicationContext applicationContext;
128
129 private String beanName;
130
131 private boolean processPropertyPlaceHolders;
132
133 private BeanNameGenerator nameGenerator;
134
135 private String defaultScope;
136
137
138
139
140
141
142
143
144
145
146
147 public void setBasePackage(String basePackage) {
148 this.basePackage = basePackage;
149 }
150
151
152
153
154
155
156
157
158
159 public void setAddToConfig(boolean addToConfig) {
160 this.addToConfig = addToConfig;
161 }
162
163
164
165
166
167
168
169
170
171
172
173
174 public void setLazyInitialization(String lazyInitialization) {
175 this.lazyInitialization = lazyInitialization;
176 }
177
178
179
180
181
182
183
184
185
186
187
188 public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
189 this.annotationClass = annotationClass;
190 }
191
192
193
194
195
196
197
198
199
200
201
202
203 public void setMarkerInterface(Class<?> superClass) {
204 this.markerInterface = superClass;
205 }
206
207
208
209
210
211
212
213
214
215
216
217 public void setExcludeFilters(List<TypeFilter> excludeFilters) {
218 this.excludeFilters = excludeFilters;
219 }
220
221
222
223
224
225
226
227
228
229
230
231 public void setRawExcludeFilters(List<Map<String, String>> rawExcludeFilters) {
232 this.rawExcludeFilters = rawExcludeFilters;
233 }
234
235
236
237
238
239
240
241
242
243
244
245 @Deprecated
246 public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
247 this.sqlSessionTemplate = sqlSessionTemplate;
248 }
249
250
251
252
253
254
255
256
257
258
259
260
261
262 public void setSqlSessionTemplateBeanName(String sqlSessionTemplateName) {
263 this.sqlSessionTemplateBeanName = sqlSessionTemplateName;
264 }
265
266
267
268
269
270
271
272
273
274
275
276 @Deprecated
277 public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
278 this.sqlSessionFactory = sqlSessionFactory;
279 }
280
281
282
283
284
285
286
287
288
289
290
291
292
293 public void setSqlSessionFactoryBeanName(String sqlSessionFactoryName) {
294 this.sqlSessionFactoryBeanName = sqlSessionFactoryName;
295 }
296
297
298
299
300
301
302
303
304
305
306
307 public void setProcessPropertyPlaceHolders(boolean processPropertyPlaceHolders) {
308 this.processPropertyPlaceHolders = processPropertyPlaceHolders;
309 }
310
311
312
313
314
315
316
317
318
319 public void setMapperFactoryBeanClass(Class<? extends MapperFactoryBean> mapperFactoryBeanClass) {
320 this.mapperFactoryBeanClass = mapperFactoryBeanClass;
321 }
322
323 @Override
324 public void setApplicationContext(ApplicationContext applicationContext) {
325 this.applicationContext = applicationContext;
326 }
327
328 @Override
329 public void setBeanName(String name) {
330 this.beanName = name;
331 }
332
333
334
335
336
337
338
339
340 public BeanNameGenerator getNameGenerator() {
341 return nameGenerator;
342 }
343
344
345
346
347
348
349
350
351
352 public void setNameGenerator(BeanNameGenerator nameGenerator) {
353 this.nameGenerator = nameGenerator;
354 }
355
356
357
358
359
360
361
362
363
364
365
366
367 public void setDefaultScope(String defaultScope) {
368 this.defaultScope = defaultScope;
369 }
370
371 @Override
372 public void afterPropertiesSet() throws Exception {
373 notNull(this.basePackage, "Property 'basePackage' is required");
374 }
375
376 @Override
377 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
378
379 }
380
381 @Override
382 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
383 if (this.processPropertyPlaceHolders) {
384 processPropertyPlaceHolders();
385 }
386
387 var scanner = new ClassPathMapperScanner(registry, getEnvironment());
388 scanner.setAddToConfig(this.addToConfig);
389 scanner.setAnnotationClass(this.annotationClass);
390 scanner.setMarkerInterface(this.markerInterface);
391 scanner.setExcludeFilters(this.excludeFilters = mergeExcludeFilters());
392 scanner.setSqlSessionFactory(this.sqlSessionFactory);
393 scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
394 scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
395 scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
396 scanner.setResourceLoader(this.applicationContext);
397 scanner.setBeanNameGenerator(this.nameGenerator);
398 scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
399 if (StringUtils.hasText(lazyInitialization)) {
400 scanner.setLazyInitialization(Boolean.parseBoolean(lazyInitialization));
401 }
402 if (StringUtils.hasText(defaultScope)) {
403 scanner.setDefaultScope(defaultScope);
404 }
405 scanner.registerFilters();
406 scanner.scan(
407 StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
408 }
409
410
411
412
413
414
415
416 private void processPropertyPlaceHolders() {
417 Map<String, PropertyResourceConfigurer> prcs = applicationContext.getBeansOfType(PropertyResourceConfigurer.class,
418 false, false);
419
420 if (!prcs.isEmpty() && applicationContext instanceof ConfigurableApplicationContext) {
421 var mapperScannerBean = ((ConfigurableApplicationContext) applicationContext).getBeanFactory()
422 .getBeanDefinition(beanName);
423
424
425
426
427 var factory = new DefaultListableBeanFactory();
428 factory.registerBeanDefinition(beanName, mapperScannerBean);
429
430 for (PropertyResourceConfigurer prc : prcs.values()) {
431 prc.postProcessBeanFactory(factory);
432 }
433
434 PropertyValues values = mapperScannerBean.getPropertyValues();
435
436 this.basePackage = getPropertyValue("basePackage", values);
437 this.sqlSessionFactoryBeanName = getPropertyValue("sqlSessionFactoryBeanName", values);
438 this.sqlSessionTemplateBeanName = getPropertyValue("sqlSessionTemplateBeanName", values);
439 this.lazyInitialization = getPropertyValue("lazyInitialization", values);
440 this.defaultScope = getPropertyValue("defaultScope", values);
441 this.rawExcludeFilters = getPropertyValueForTypeFilter("rawExcludeFilters", values);
442 }
443 this.basePackage = Optional.ofNullable(this.basePackage).map(getEnvironment()::resolvePlaceholders).orElse(null);
444 this.sqlSessionFactoryBeanName = Optional.ofNullable(this.sqlSessionFactoryBeanName)
445 .map(getEnvironment()::resolvePlaceholders).orElse(null);
446 this.sqlSessionTemplateBeanName = Optional.ofNullable(this.sqlSessionTemplateBeanName)
447 .map(getEnvironment()::resolvePlaceholders).orElse(null);
448 this.lazyInitialization = Optional.ofNullable(this.lazyInitialization).map(getEnvironment()::resolvePlaceholders)
449 .orElse(null);
450 this.defaultScope = Optional.ofNullable(this.defaultScope).map(getEnvironment()::resolvePlaceholders).orElse(null);
451 }
452
453 private Environment getEnvironment() {
454 return this.applicationContext.getEnvironment();
455 }
456
457 private String getPropertyValue(String propertyName, PropertyValues values) {
458 var property = values.getPropertyValue(propertyName);
459
460 if (property == null) {
461 return null;
462 }
463
464 var value = property.getValue();
465
466 if (value == null) {
467 return null;
468 }
469 if (value instanceof String) {
470 return value.toString();
471 }
472 if (value instanceof TypedStringValue) {
473 return ((TypedStringValue) value).getValue();
474 }
475 return null;
476 }
477
478 @SuppressWarnings("unchecked")
479 private List<Map<String, String>> getPropertyValueForTypeFilter(String propertyName, PropertyValues values) {
480 var property = values.getPropertyValue(propertyName);
481 Object value;
482 if (property == null || (value = property.getValue()) == null || !(value instanceof List<?>)) {
483 return null;
484 }
485 return (List<Map<String, String>>) value;
486 }
487
488 private List<TypeFilter> mergeExcludeFilters() {
489 List<TypeFilter> typeFilters = new ArrayList<>();
490 if (this.rawExcludeFilters == null || this.rawExcludeFilters.isEmpty()) {
491 return this.excludeFilters;
492 }
493 if (this.excludeFilters != null && !this.excludeFilters.isEmpty()) {
494 typeFilters.addAll(this.excludeFilters);
495 }
496 try {
497 for (Map<String, String> typeFilter : this.rawExcludeFilters) {
498 typeFilters.add(
499 createTypeFilter(typeFilter.get("type"), typeFilter.get("expression"), this.getClass().getClassLoader()));
500 }
501 } catch (ClassNotFoundException exception) {
502 throw new RuntimeException("ClassNotFoundException occur when to load the Specified excludeFilter classes.",
503 exception);
504 }
505 return typeFilters;
506 }
507
508 @SuppressWarnings("unchecked")
509 private TypeFilter createTypeFilter(String filterType, String expression, @Nullable ClassLoader classLoader)
510 throws ClassNotFoundException {
511
512 if (this.processPropertyPlaceHolders) {
513 expression = this.getEnvironment().resolvePlaceholders(expression);
514 }
515
516 switch (filterType) {
517 case "annotation":
518 Class<?> filterAnno = ClassUtils.forName(expression, classLoader);
519 if (!Annotation.class.isAssignableFrom(filterAnno)) {
520 throw new IllegalArgumentException(
521 "Class is not assignable to [" + Annotation.class.getName() + "]: " + expression);
522 }
523 return new AnnotationTypeFilter((Class<Annotation>) filterAnno);
524 case "custom":
525 Class<?> filterClass = ClassUtils.forName(expression, classLoader);
526 if (!TypeFilter.class.isAssignableFrom(filterClass)) {
527 throw new IllegalArgumentException(
528 "Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression);
529 }
530 return (TypeFilter) BeanUtils.instantiateClass(filterClass);
531 case "assignable":
532 return new AssignableTypeFilter(ClassUtils.forName(expression, classLoader));
533 case "regex":
534 return new RegexPatternTypeFilter(Pattern.compile(expression));
535 case "aspectj":
536 return new AspectJTypeFilter(expression, classLoader);
537 default:
538 throw new IllegalArgumentException("Unsupported filter type: " + filterType);
539 }
540 }
541
542 }