1. 程式人生 > >Spring Boot自定義註解掃描器 Spring Boot自定義註解掃描器

Spring Boot自定義註解掃描器 Spring Boot自定義註解掃描器

Spring Boot自定義註解掃描器

2018年08月15日 14:37:52 閱讀數:502
																														</div>
			<div class="operating">
													</div>
		</div>
	</div>
</div>
<article>
	<div id="article_content" class="article_content clearfix csdn-tracking-statistics" data-pid="blog" data-mod="popu_307" data-dsm="post">
							<div class="article-copyright">
				版權宣告:					https://blog.csdn.net/Dongguabai/article/details/81702958				</div>
							            <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-7f5a1a725b.css">
					<div class="htmledit_views">
            <p>之前在整合Spring Boot和tkMybatis的時候使用了這個註解:</p>

這個還挺實用的,會將指定包下的相應的類載入至Spring容器中,剛好我這邊也有一個獨立抽取出來的許可權模組也想實現這樣的功能(當然可以使用@EnableXX的方式,但是注入的元件太多了,直接包掃描直接點),而不是使用@ComponentScan或者是scanBasePackages必須指定某個包,這樣顯得太low了,使用註解自動掃描多好。

先來看看@MapperScan是怎麼實現的:

沒有什麼特別的,引入了MapperScannerRegistrar:

中間有很多其他的程式碼都不用管,直接看最關鍵的:

定義了一個Mapper的Scanner:

然後呼叫doScan()方法即可:

而doScan()方法實際上就是Spring的核心掃描器ClassPathBeanDefinitionScanner的方法,而tkMybatis中定義了一個ClassPathMapperScanner繼承了ClassPathBeanDefinitionScanne重寫了doScan()方法,我們就可以照葫蘆畫瓢了。

自定義註解

自定義Registrar


  
  1. import lombok.extern.slf4j.Slf4j;
  2. import org.springframework.beans.factory.support.BeanDefinitionRegistry;
  3. import org.springframework.context.EnvironmentAware;
  4. import org.springframework.context.ResourceLoaderAware;
  5. import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
  6. import org.springframework.core.annotation.AnnotationAttributes;
  7. import org.springframework.core.env.Environment;
  8. import org.springframework.core.io.ResourceLoader;
  9. import org.springframework.core.type.AnnotationMetadata;
  10. import org.springframework.util.StringUtils;
  11. import java.util.ArrayList;
  12. import java.util.List;
  13. /**
  14. * @author Dongguabai
  15. * @date 2018/8/15 13:36
  16. */
  17. @Slf4j
  18. public class DgbSecurityScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
  19. private ResourceLoader resourceLoader;
  20. private Environment environment;
  21. @Override
  22. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  23. AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(DgbSecurityScan.class.getName()));
  24. ClassPathDgbSecurityScanner scanner = new ClassPathDgbSecurityScanner(registry);
  25. // this check is needed in Spring 3.1
  26. if (resourceLoader != null) {
  27. scanner.setResourceLoader(resourceLoader);
  28. }
  29. List<String> basePackages = new ArrayList<String>();
  30. for (String pkg : annoAttrs.getStringArray( "basePackages")) {
  31. if (StringUtils.hasText(pkg)) {
  32. basePackages.add(pkg);
  33. }
  34. }
  35. scanner.doScan(StringUtils.toStringArray(basePackages));
  36. }
  37. @Override
  38. public void setEnvironment(Environment environment) {
  39. this.environment = environment;
  40. }
  41. @Override
  42. public void setResourceLoader(ResourceLoader resourceLoader) {
  43. this.resourceLoader = resourceLoader;
  44. }
  45. }

自定義Scanner


  
  1. import org.springframework.beans.factory.config.BeanDefinitionHolder;
  2. import org.springframework.beans.factory.support.BeanDefinitionRegistry;
  3. import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
  4. import org.springframework.core.env.Environment;
  5. import org.springframework.core.io.ResourceLoader;
  6. import org.springframework.lang.Nullable;
  7. import java.util.Arrays;
  8. import java.util.Set;
  9. /**
  10. * @author Dongguabai
  11. * @date 2018/8/15 13:40
  12. */
  13. public class ClassPathDgbSecurityScanner extends ClassPathBeanDefinitionScanner {
  14. public ClassPathDgbSecurityScanner(BeanDefinitionRegistry registry) {
  15. super(registry);
  16. }
  17. public ClassPathDgbSecurityScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
  18. super(registry, useDefaultFilters);
  19. }
  20. public ClassPathDgbSecurityScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment) {
  21. super(registry, useDefaultFilters, environment);
  22. }
  23. public ClassPathDgbSecurityScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, @Nullable ResourceLoader resourceLoader) {
  24. super(registry, useDefaultFilters, environment, resourceLoader);
  25. }
  26. /**
  27. * Calls the parent search that will search and register all the candidates.
  28. * Then the registered objects are post processed to set them as
  29. * MapperFactoryBeans
  30. */
  31. @Override
  32. public Set<BeanDefinitionHolder> doScan(String... basePackages) {
  33. Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
  34. if (beanDefinitions.isEmpty()) {
  35. logger.warn( "No DgbSecurity Spring Componet was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
  36. }
  37. return beanDefinitions;
  38. }
  39. }

最後將註解放到Spring Boot啟動類上即可。

因為是臨時突然想到這個,程式碼應該有不少可以優化的地方,以後再看吧。

========================================================================================

使用這個方式用在基於Spring Security的許可權模組是可以的,但是用在基於Quartz的排程模組一直出問題,經過debug發現是可以掃描成功並且是可以註冊的,但是啟動過程中執行排程任務的時候一直出問題,異常顯示為create Bean找不到那個Bean,一直無法理解。但是在別的模組是可以正常使用的。

				<script>
					(function(){
						function setArticleH(btnReadmore,posi){
							var winH = $(window).height();
							var articleBox = $("div.article_content");
							var artH = articleBox.height();
							if(artH > winH*posi){
								articleBox.css({
									'height':winH*posi+'px',
									'overflow':'hidden'
								})
								btnReadmore.click(function(){
									articleBox.removeAttr("style");
									$(this).parent().remove();
								})
							}else{
								btnReadmore.parent().remove();
							}
						}
						var btnReadmore = $("#btn-readmore");
						if(btnReadmore.length>0){
							if(currentUserName){
								setArticleH(btnReadmore,3);
							}else{
								setArticleH(btnReadmore,1.2);
							}
						}
					})()
				</script>
				</article>