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);
    }
}

结果:

image

方式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);
    }
}

结果:

image

方式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);
    }
}

结果:

image

方式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);
    }
}

结果:

image

方式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();
		}
	}
}

posted @ 2023-05-03 22:08  sunpeiyu  阅读(79)  评论(0编辑  收藏  举报