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