前言
Spring
可以自动将@Component
注解修饰的类加载为Bean
.
比如MyController
这个类, 就会加载为名称是myController
的Bean
.
但是, 如果在不同的模块下, 不同的包下, 有着相同文件名的类, 就会造成BeanName
冲突。
1 2 3 4 5 6 7
| - com.ahao.project - moduleA - IndexController.java - moduleAService.java - moduleB - IndexController.java - moduleBService.java
|
解决方案
为什么我们使用Java
类的时候不会发生冲突呢?
因为import
将包名导入了, 否则我们需要输入包名.类名
才能使用这个类。
引用这个思路, 将BeanName
也设置成包名.类名
的形式。
1 2 3 4
| <?xml version="1.0" encoding="UTF-8"?> <beans> <context:component-scan base-package="com.ahao" name-generator="com.ahao.core.spring.bean.PackageBeanNameGenerator"/> </beans>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class PackageBeanNameGenerator extends AnnotationBeanNameGenerator { private static final Logger logger = LoggerFactory.getLogger(PackageBeanNameGenerator.class);
@Override public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { String beanClassName = Introspector.decapitalize(definition.getBeanClassName()); if(StringUtils.startsWith(beanClassName, getPackageNamePrefix())) { logger.debug("初始化Bean: " + beanClassName); return beanClassName; } return super.generateBeanName(definition, registry); }
private String getPackageNamePrefix() { String separator = "."; String[] splits = StringUtils.split(this.getClass().getPackage().getName(), separator); String prefix = Arrays.stream(splits).limit(3) .collect(Collectors.joining(separator)); return prefix; } }
|
Mybatis使用BeanNameGenerator
在Spring
整合发现Mybatis
的BeanName
生成没有使用BeanNameGenerator
。
1 2 3 4
| <context:component-scan base-package="com.ahao" use-default-filters="false" name-generator="com.ahao.core.beans.PackageBeanNameGenerator"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/> </context:component-scan>
|
1 2 3 4
| @Repository public interface ModuleDAO { List<String> getNames(); }
|
在调试时,Mybatis
的代理类没有使用@Repository
注解,所以include-filter
没有扫描到代理类。
在Stack Overflow
提问也没人回。
后来自己找到了解决方法, 在配置MapperScannerConfigurer
时注入NameGenerator
即可。
1 2 3 4 5 6 7 8 9 10
| <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <property name="basePackage" value="com.ahao.**.dao"/> <property name="nameGenerator"> <bean class="com.ahao.core.spring.beans.PackageBeanNameGenerator"/> </property> </bean>
|
Spring Boot 基于注解的配置
Spring Boot
分为两种启动方式
- 通过
main
方法启动内嵌Tomcat
- 打包
war
包启动外置Tomcat
直接看代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication app = new SpringApplication(Application.class); app.setBeanNameGenerator(new PackageBeanNameGenerator()); app.run(args); logger.info("Spring Boot 启动成功!"); } }
public class AppServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(Application.class) .beanNameGenerator(new PackageBeanNameGenerator()); } }
|
同样的, Mybatis
依然需要单独配置, 重点在@MapperScan
注解
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Configuration @ConditionalOnProperty(prefix = "ahao.datasource", name = "open", havingValue = "false", matchIfMissing = true) @EnableTransactionManagement @MapperScan(basePackages = {"com.ahao.**.dao"}, nameGenerator = PackageBeanNameGenerator.class) public class DataSourceConfig { @Bean public DruidDataSource dataSource(DruidProperties druidProperties) { DruidDataSource dataSource = new DruidDataSource(); druidProperties.config(dataSource); return dataSource; } }
|
参考资料