条条大路通罗马
前提:怕读者没有头绪,请在https://blog.csdn.net/dong19891210/article/details/105697175的情况下看
Spring bean有以下几种注册方式:
1. 通过GenericBeanDefinition注册
示例代码:
消息辅助类
public class Message {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void print() {
System.out.println("消息是: " + message);
}
}
注册测试类:
/**
*
* @author dgm
* @describe "GenericBeanDefinition注册bean定义"
* @date 2020年4月27日
*/
public class GenericBeanDefinitionExample {
public static void main (String[] args) {
DefaultListableBeanFactory context =
new DefaultListableBeanFactory();
//在此构造bean定义
GenericBeanDefinition gbd = new GenericBeanDefinition();
gbd.setBeanClass(Message.class);
//
MutablePropertyValues mpv = new MutablePropertyValues();
mpv.add("message", "this is a bean");
//注册到环境上下文
context.registerBeanDefinition("myBean", gbd);
Message bean = context.getBean(Message.class);
bean.print();
Message myBean = (Message) context.getBean("myBean");
myBean.print();
}
}
结果:
2. 通过BeanDefinitionBuilder注册
/**
*
* @author dgm
* @describe ""
* @date 2020年4月16日
*/
public class BeanDefinitionBuilderExample {
public static void main (String[] args) {
DefaultListableBeanFactory context =
new DefaultListableBeanFactory();
//用到了构建者模式
BeanDefinitionBuilder b =
BeanDefinitionBuilder.rootBeanDefinition(Message.class)
.addPropertyValue("message", "this is a bean");
context.registerBeanDefinition("myBean", b.getBeanDefinition());
Message bean = context.getBean(Message.class);
bean.print();
Message myBean = (Message) context.getBean("myBean");
myBean.print();
}
}
效果同第一种情况,只是用的是BeanDefinitionBuilder模式
3. 通过BeanFactoryPostProcessor
public class MessageBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
// TODO Auto-generated method stub
GenericBeanDefinition gbd = new GenericBeanDefinition();
gbd.setBeanClass(Message.class);
MutablePropertyValues mpv = new MutablePropertyValues();
mpv.add("message", "this is a BeanFactoryPostProcessor bean");
gbd.setPropertyValues(mpv);
((DefaultListableBeanFactory) beanFactory).registerBeanDefinition(
"myBean", gbd);
}
}
配置类
@Configuration
public class MyConfig {
@Bean
MessageBeanFactoryPostProcessor messageConfigBean () {
return new MessageBeanFactoryPostProcessor();
}
}
测试类:
/**
*
* @author dgm
* @describe "测试BeanFactoryPostProcessor"
* @date 2020年4月27日
*/
public class BeanFactoryPostProcessorExample {
public static void main (String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class);
//MyBean bean = context.getBean(MyBean.class);
//bean.doSomething();
//bean.doOtherSomething();
Message bean = context.getBean(Message.class);
bean.print();
Message myBean = (Message) context.getBean("myBean");
myBean.print();
}
}
效果:
4. 通过BeanDefinitionRegistryPostProcessor
public class MessageBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
// TODO Auto-generated method stub
}
@Override
public void postProcessBeanDefinitionRegistry(
BeanDefinitionRegistry registry) throws BeansException {
// TODO Auto-generated method stub
GenericBeanDefinition gbd = new GenericBeanDefinition();
gbd.setBeanClass(Message.class);
MutablePropertyValues mpv = new MutablePropertyValues();
mpv.add("message", "this is a BeanDefinitionRegistryPostProcessor bean");
gbd.setPropertyValues(mpv);
registry.registerBeanDefinition(
"myBean", gbd);
}
}
配置类
@Configuration
public class MyConfig {
@Bean
ConfigBeanFactoryPostProcessor myConfigBean () {
return new ConfigBeanFactoryPostProcessor();
}
/*@Bean
MessageBeanFactoryPostProcessor messageBeanFactoryPostProcessor () {
return new MessageBeanFactoryPostProcessor();
}*/
@Bean
MessageBeanDefinitionRegistryPostProcessor messageBeanDefinitionRegistryPostProcessor () {
return new MessageBeanDefinitionRegistryPostProcessor();
}
}
测试类:
public class BeanDefinitionRegistryPostProcessorExample {
public static void main (String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class);
//MyBean bean = context.getBean(MyBean.class);
//bean.doSomething();
//bean.doOtherSomething();
Message bean = context.getBean(Message.class);
bean.print();
Message myBean = (Message) context.getBean("myBeanDefinitionRegistry");
myBean.print();
}
}
效果:
5. 通过Import
import类型有以下几类:
5.1 ImportSelector导入
public interface PrintService {
void print(String msg);
}
public class PrintServiceImpl implements PrintService{
@Override
public void print(String msg) {
System.out.println("Hello : " + msg);
}
}
//重点,实现了ImportSelector
public class MessageImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// TODO Auto-generated method stub
return new String[] {PrintServiceImpl.class.getName()};
}
}
//配置类
@Configuration
@Import(MessageImportSelector.class)
public class MessageImportSelectorConfiguration {
}
测试代码和效果:
注:我是以demo演示(selectImports()写死了),实际场景中可以动态注入bean,想象空间很大。
5.2 ImportBeanDefinitionRegistrar注册
/**
*
* @author dgm
* @describe "实现ImportBeanDefinitionRegistrar "
* @date 2020年4月28日
*/
public class MessageImportBeanDefinitionRegistrar implements
ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
// 只以演示为例,现实场景通过importingClassMetadata拿到动态数据
GenericBeanDefinition gbd = new GenericBeanDefinition();
gbd.setBeanClass(Message.class);
MutablePropertyValues mpv = new MutablePropertyValues();
mpv.add("message", "this is a ImportBeanDefinitionRegistrar bean");
gbd.setPropertyValues(mpv);
registry.registerBeanDefinition("myBean", gbd);
GenericBeanDefinition printBeanDefinition = new GenericBeanDefinition();
printBeanDefinition.setBeanClass(PrintServiceImpl.class);
registry.registerBeanDefinition("printBean", printBeanDefinition);
}
}
配置类:
@Configuration
@Import(MessageImportBeanDefinitionRegistrar.class)
public class MessageImportBeanDefinitionRegistrarConfiguration {
}
测试
/**
*
* @author dgm
* @describe "测试ImportBeanDefinitionRegistrar"
* @date 2020年4月28日
*/
public class ImportBeanDefinitionRegistrarDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
MessageImportBeanDefinitionRegistrarConfiguration.class);
String[] beanNames = applicationContext.getBeanDefinitionNames();
System.out.println(Arrays.asList(beanNames));
Message bean = applicationContext.getBean(Message.class);
bean.print();
PrintService ps = (PrintService) applicationContext
.getBean(PrintService.class);
ps.print("ImportBeanDefinitionRegistrar demo");
}
}
5.3 组合式,比如kafak集成到spring
/**
*
* @author dgm
* @describe "实现了ImportSelector接口的导入"
* @date 2020年4月28日
*/
public class MessageImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// TODO Auto-generated method stub
//return new String[] {PrintServiceImpl.class.getName()};
//不再写死了,用上元数据
Map annotationAttributes = importingClassMetadata.getAnnotationAttributes(PrintServiceScan.class.getName());
String[] basePackages = (String[]) annotationAttributes.get("basePackages");
if (basePackages == null || basePackages.length == 0) {//PrintServiceScan的basePackages默认为空数组
String basePackage = null;
try {
basePackage = Class.forName(importingClassMetadata.getClassName()).getPackage().getName();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
basePackages = new String[] {basePackage};
}
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
TypeFilter printServiceFilter = new AssignableTypeFilter(PrintService.class);
scanner.addIncludeFilter(printServiceFilter);
Set classes = new HashSet<>();
for (String basePackage : basePackages) {
scanner.findCandidateComponents(basePackage).forEach(beanDefinition -> classes.add(beanDefinition.getBeanClassName()));
}
return classes.toArray(new String[classes.size()]);
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MessageImportSelector.class)
public @interface PrintServiceScan {
@AliasFor("value")
String[] basePackages() default {};
@AliasFor("basePackages")
String[] value() default {};
}
/**
*
* @author dgm
* @describe ""
* @date 2020年4月28日
*/
@Configuration
//@Import(MessageImportSelector.class)
@PrintServiceScan("spring.service.impl")
public class MessageImportSelectorConfiguration {
}
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Indexed;
import spring.config.MessageImportSelectorConfiguration;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MessageImportSelectorConfiguration.class)
public @interface EnablePrintService {
}
最终测试:
/**
*
* @author dgm
* @describe "测试组合式ImportSelector"
* @date 2020年4月28日
*/
public class ImportSelectorDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MessageImportSelectorConfiguration.class);
PrintService ps = (PrintService) applicationContext.getBean(PrintService.class);
ps.print("组合式 ImportSelector demo");
}
}
附详情参考源码ConfigurationClassParser类处理如何处理不同的import
总结:我是层层递进写的,spring bean 注册几种方式:GenericBeanDefinition,BeanDefinitionBuilder(设计模式无处不在),BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor,Import型。
参考:
0. https://www.programcreek.com/java-api-examples/index.php?class=org.springframework.beans.factory.support.GenericBeanDefinition&method=setAttribute
1. BeanDefinitionBuilder.java https://alvinalexander.com/java/jwarehouse/spring-framework-2.5.3/src/org/springframework/beans/factory/support/BeanDefinitionBuilder.java.shtml
2. bean definition for automatic FilterRegistrationBeanFactory http://dimafeng.com/2015/11/27/dynamic-bean-definition/
3. 使用@import导入实现了ImportBeanDefinitionRegistrar接口的类 https://blog.51cto.com/14672031/2474904
4. Spring向容器注册Bean的高级应用 https://cloud.tencent.com/developer/article/1497795
5. How to integrate Jdon Framework with Spring http://en.jdon.com/springIntegration.html
6. Spring Boot dynamically injects beans through importbeandefinitionregister
https://programmer.help/blogs/spring-boot-dynamically-injects-beans-through-importbeandefinitionregister.html
7. Spring - Using ImportBeanDefinitionRegistrar
https://www.logicbig.com/tutorials/spring-framework/spring-core/import-bean-registrar.html
8. importbeandefinitionregistrar https://www.javatips.net/api/org.springframework.context.annotation.importbeandefinitionregistrar
9. MessagingGatewayRegistrar.java http://javadox.com/org.springframework.integration/spring-integration-core/4.0.4.RELEASE/org/springframework/integration/config/MessagingGatewayRegistrar.java.html
10. Spring - Dynamically register beans https://www.logicbig.com/tutorials/spring-framework/spring-core/bean-definition.html