SpringBoot注入bean的方式
方式1:@ComponentScan扫描包注入
一般@ComponentScan注解搭配@Component、@Service、@Controller等注入。因为我们写的bean都和启动类在同一个包下,所以扫描包注入注解@ComponentScan无需加入。但是如果我们不和启动类在同一个包下,那么我们需要提供@ComponentScan扫描包注解,扫描需要注入的bean。
方式2:@Import注解注入bean
public class FirstSunpyBean {
}
public class SecondSunpyBean {
}
@Import({FirstSunpyBean.class, SecondSunpyBean.class})
@Slf4j
@Service
public class MenuServiceImpl {
public List<MenuDTO> listMenu() throws Exception {
MenuMapper menuMapper = SpringUtils.getBean("menuMapper", MenuMapper.class);
List<MenuEntity> menuEntityList = menuMapper.selectMenuList();
log.info("==================== menuEntityList : {}", menuEntityList);
boolean flag1 = SpringUtils.containsBean("com.sunpeiyu.visualweb.config.FirstSunpyBean");
boolean flag2 = SpringUtils.containsBean("com.sunpeiyu.visualweb.config.SecondSunpyBean");
log.info("==================== FirstSunpyBean = {}", flag1);
log.info("==================== SecondSunpyBean = {}", flag2);
return CopyUtils.copyListByShallow(menuEntityList, MenuDTO.class);
}
}
结果:
方式3:实现ImportSelector接口注入多个bean
public class FirstSunpyBean {
}
public class SecondSunpyBean {
}
public class SunpyBeanSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {FirstSunpyBean.class.getName(), SecondSunpyBean.class.getName()};
}
}
@Import(SunpyBeanSelector.class)
@Slf4j
@Service
public class MenuServiceImpl {
public List<MenuDTO> listMenu() throws Exception {
MenuMapper menuMapper = SpringUtils.getBean("menuMapper", MenuMapper.class);
List<MenuEntity> menuEntityList = menuMapper.selectMenuList();
log.info("==================== menuEntityList : {}", menuEntityList);
boolean flag1 = SpringUtils.containsBean("com.sunpeiyu.visualweb.config.FirstSunpyBean");
boolean flag2 = SpringUtils.containsBean("com.sunpeiyu.visualweb.config.SecondSunpyBean");
log.info("==================== FirstSunpyBean = {}", flag1);
log.info("==================== SecondSunpyBean = {}", flag2);
return CopyUtils.copyListByShallow(menuEntityList, MenuDTO.class);
}
}
结果:
方式4:实现ImportBeanDefinitionRegistrar接口注入bean
public class FirstSunpyBean {
}
public class SecondSunpyBean {
}
public class SunpyBeanRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
// ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry, importBeanNameGenerator);
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(FirstSunpyBean.class);
registry.registerBeanDefinition("com.sunpeiyu.visualweb.config.FirstSunpyBean", rootBeanDefinition);
RootBeanDefinition rootBeanDefinition1 = new RootBeanDefinition();
rootBeanDefinition1.setBeanClass(SecondSunpyBean.class);
registry.registerBeanDefinition("com.sunpeiyu.visualweb.config.SecondSunpyBean", rootBeanDefinition1);
}
}
@Import(SunpyBeanRegister.class)
@Slf4j
@Service
public class MenuServiceImpl {
public List<MenuDTO> listMenu() throws Exception {
MenuMapper menuMapper = SpringUtils.getBean("menuMapper", MenuMapper.class);
List<MenuEntity> menuEntityList = menuMapper.selectMenuList();
log.info("==================== menuEntityList : {}", menuEntityList);
boolean flag1 = SpringUtils.containsBean("com.sunpeiyu.visualweb.config.FirstSunpyBean");
boolean flag2 = SpringUtils.containsBean("com.sunpeiyu.visualweb.config.SecondSunpyBean");
log.info("==================== FirstSunpyBean = {}", flag1);
log.info("==================== SecondSunpyBean = {}", flag2);
return CopyUtils.copyListByShallow(menuEntityList, MenuDTO.class);
}
}
结果:
方式5,实现DeferredImportSelector接口注入bean
public class FirstSunpyBean {
}
public class SecondSunpyBean {
}
public class SunpyBeanDeferredSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {FirstSunpyBean.class.getName(), SecondSunpyBean.class.getName()};
}
}
@Import(SunpyBeanDeferredSelector.class)
@Slf4j
@Service
public class MenuServiceImpl {
public List<MenuDTO> listMenu() throws Exception {
MenuMapper menuMapper = SpringUtils.getBean("menuMapper", MenuMapper.class);
List<MenuEntity> menuEntityList = menuMapper.selectMenuList();
log.info("==================== menuEntityList : {}", menuEntityList);
boolean flag1 = SpringUtils.containsBean("com.sunpeiyu.visualweb.config.FirstSunpyBean");
boolean flag2 = SpringUtils.containsBean("com.sunpeiyu.visualweb.config.SecondSunpyBean");
log.info("==================== FirstSunpyBean = {}", flag1);
log.info("==================== SecondSunpyBean = {}", flag2);
return CopyUtils.copyListByShallow(menuEntityList, MenuDTO.class);
}
}
结果:
方式6:FactoryBean注入bean
@Slf4j
public class SunpyBean implements FactoryBean<SunpyBean> {
@Override
public SunpyBean getObject() throws Exception {
log.info(">>>>>>>>>>>>>>>>>>>>>>>>>> init SunpyBean <<<<<<<<<<<<<<");
return new SunpyBean();
}
@Override
public Class<?> getObjectType() {
return SunpyBean.class;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
注意事项
- bean名称问题:
我们如果不指定bean的名称,那么默认bean的名称为包名+类名(不带.class)。所以如果我们不论是否指定了类型,一定要保持存放和获取的时候类名一致(就是查看DefaultListableBeanFactory中的beanDefinitionMap存放的key)
自动注入bean的源码
ConfigurationClassParser.processImports(configClass, sourceClass, getImports(sourceClass), filter, true),在这个方法中实现的。
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
-
想要搞清楚springboot自动装配前因后果:
SpringBoot自动装配源码 -
建议,想要搞清楚springboot自动装配源码,还是对springboot的运行流程有个认识:
SpringBoot源码