解决Spring Boot 多模块注入访问不到jar包中的Bean问题
情景描述
一个聚合项目spring-security-tutorial,其中包括4个module,pom如下所示:
4.0.0 com.github.jdkong.security spring-security-tutorial 1.0-SNAPSHOT pom `` security-core security-app security-browser security-demo
在此项目中,子项目security-browser是一个简单的maven项目,打成jar包,供security-demo使用,security-demo项目是一个springboot项目。
问题描述
在security-browser项目中自动注入了一个配置类,如下所示:
/**
*@authorjdkong
*/
@Slf4j
@Configuration
publicclassBrowserSecurityConfigextendsWebSecurityConfigurerAdapter{
@Override
protectedvoidconfigure(HttpSecurityhttp)throwsException{
http.formLogin()
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
在security-demo中使用此配置类时,不起作用。
问题分析
导致此类问题的主要原因是,此类不在SpringBoot的组件扫描范围之内。
1.关于SpringBoot自动注入及组件扫描
在平时使用SpringBoot时,常常会使用到@Configuration,@Contoller,@Service,@Component等注解,被添加这些注解的类,在SpringBoot启动时,会自动被Spring容器管理起来。
上面提到了,添加了一些注解的类会在SpringBoot容器启动时,被加载到Spring容器中。那么,组件扫描的作用就是:当SpringBoot启动时,根据定义的扫描路径,把符合扫描规则的类装配到spring容器中。
2.SpringBoot中@ComponentScan
简单的介绍了@ComponentScan的基础作用,这个注解为我们使用提供了一些可自定义配置属性,先来看看@ComponentScan注解源码:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public@interfaceComponentScan{
//指定扫描包的位置(同:basePackages属性),可以是单个路径,也可以是扫描的路径数组
@AliasFor("basePackages")
String[]value()default{};
//指定扫描包的位置(同:value属性)
@AliasFor("value")
String[]basePackages()default{};
//指定具体的扫描的类
Class>[]basePackageClasses()default{};
//bean的名称的生成器
ClassnameGenerator()defaultBeanNameGenerator.class;
ClassscopeResolver()defaultAnnotationScopeMetadataResolver.class;
ScopedProxyModescopedProxy()defaultScopedProxyMode.DEFAULT;
//控制符合组件检测条件的类文件默认是包扫描下的**/*.class
StringresourcePattern()default"**/*.class";
//是否开启对@Component,@Repository,@Service,@Controller的类进行检测
booleanuseDefaultFilters()defaulttrue;
//包含的过滤条件
//1.FilterType.ANNOTATION:按照注解过滤
//2.FilterType.ASSIGNABLE_TYPE:按照给定的类型
//3.FilterType.ASPECTJ:使用ASPECTJ表达式
//4.FilterType.REGEX:正则
//5.FilterType.CUSTOM:自定义规则
ComponentScan.Filter[]includeFilters()default{};
//排除的过滤条件,用法和includeFilters一样
ComponentScan.Filter[]excludeFilters()default{};
booleanlazyInit()defaultfalse;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public@interfaceFilter{
FilterTypetype()defaultFilterType.ANNOTATION;
@AliasFor("classes")
Class>[]value()default{};
@AliasFor("value")
Class>[]classes()default{};
String[]pattern()default{};
}
}
总结一下@ComponentScan的常用方式如下:
通过使用value,basePackages属性来指定扫描范围;
自定扫描路径下边带有@Controller,@Service,@Repository,@Component注解加入Spring容器
通过includeFilters加入扫描路径下没有以上注解的类加入spring容器
通过excludeFilters过滤出不用加入spring容器的类
自定义增加了@Component注解的注解方式
3.SpringBoot中@SpringBootApplication
在创建SpringBoot项目之后,在默认的启动类上会被添加@SpringBootApplication注解,这个注解默认帮我们开启一些自动配置的功能,比如:基于Java的Spring配置,组件扫描,特别是用于启用SpringBoot的自动配置功能。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration//允许自动配置
@ComponentScan(
excludeFilters={@Filter(//定义排除规则
type=FilterType.CUSTOM,//采用自定义的方式
classes={TypeExcludeFilter.class}//自定义实现逻辑
),@Filter(//同上
type=FilterType.CUSTOM,
classes={AutoConfigurationExcludeFilter.class}
)}
)
public@interfaceSpringBootApplication{
//为@EnableAutoConfiguration添加exclude规则
@AliasFor(
annotation=EnableAutoConfiguration.class,
attribute="exclude"
)
Class>[]exclude()default{};
//为@EnableAutoConfiguration添加excludeName规则
@AliasFor(
annotation=EnableAutoConfiguration.class,
attribute="excludeName"
)
String[]excludeName()default{};
//为@ComponentScan添加basePackages规则
@AliasFor(
annotation=ComponentScan.class,
attribute="basePackages"
)
String[]scanBasePackages()default{};
//为@ComponentScan添加basePackageClasses规则
@AliasFor(
annotation=ComponentScan.class,
attribute="basePackageClasses"
)
Class>[]scanBasePackageClasses()default{};
}
从上面的源码部分可以看到,@SpringBootApplication是一个组合注解,也就相当于使用一个@SpringBootApplication可以替代@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan几个注解联合使用。
注:此注释从SpringBoot1.2开始提供,这意味着如果你运行的是较低的版本,并且如果你需要这些功能,你需要手动添加@Configuration,@CompnentScan和@EnableAutoConfiguration。
那么,可能会有这样的问题,我只是使用了一个@SpringBootApplication注解,但是我如何对@ComponentScan的属性做自定义配置呢?
当然,Spring团队已经很好的解决了这个问题,在@SpringBootApplication注解类中的属性上添加@AliasFor注解,从而实现通过对@SpringBootApplication中的属性进行自定义,达到对对应的注解的属性的自定义。
比如:
@AliasFor(
annotation=ComponentScan.class,
attribute="basePackages"
)
String[]scanBasePackages()default{};
这段代码就是实现,通过对@SpringBootApplication的属性scanBasePackages,实现对@ComponentScan中的属性basePackages进行自定义。
4.回答开篇问题
先看看项目结构,项目入口文件在子项目security-demo中,并且入口类所在包位置为:packagecom.github.jdkong.security。
也就是说,在不做任何配置的情况下,此项目只会扫描当前包路径及其子路径下的文件,并将符合条件的对象注入到容器中管理。
再看看配置文件所在的包路径位置:packagecom.github.jdkong.browser.config,可见此包路径并不在项目扫描的路径范围之内。
这也就导致了,我们定义的配置类,虽然加了@Configuration也不会对我们的项目起到作用。
可以对项目注解进行稍微修改,制定扫描包的范围,就可以简单的解决这个问题。如下:
@SpringBootApplication(scanBasePackages="com.github.jdkong")
publicclassSecurityApplication{
publicstaticvoidmain(String[]args){
SpringApplication.run(SecurityApplication.class,args);
}
}
5.补充说明:@AliasFor
在Spring注解中,经常会发现很多注解的不同属性起着相同的作用,比如@ComponentScan的value属性和basePackages属性。所以在使用的时候就需要做一些基本的限制,比如value和basePackages的值不能冲突,比如任意设置value或者设置basePackages属性的值,都能够通过另一个属性来获取值等等。为了统一处理这些情况,Spring创建了@AliasFor标签。
以上这篇解决SpringBoot多模块注入访问不到jar包中的Bean问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。