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