Spring Bean注册的几种方式

条条大路通罗马

前提:怕读者没有头绪,请在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(); } }

结果:

Spring Bean注册的几种方式_第1张图片

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

效果:

Spring Bean注册的几种方式_第2张图片

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

效果:

Spring Bean注册的几种方式_第3张图片

 

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 { } 

测试代码和效果:

 Spring Bean注册的几种方式_第4张图片

注:我是以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"); } } 

Spring Bean注册的几种方式_第5张图片​ 

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

 Spring Bean注册的几种方式_第6张图片

附详情参考源码ConfigurationClassParser类处理如何处理不同的import

Spring Bean注册的几种方式_第7张图片

 

总结:我是层层递进写的,spring bean 注册几种方式:GenericBeanDefinition,BeanDefinitionBuilder(设计模式无处不在),BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor,Import型。

灵活性很强,很难达成统一(连交通规矩都难一统,更何况这),条条大路通罗马,没有最好只有合适,如果让你选择注册bean或扩展性开发或集成第三方,你会选哪种呢,可以参考mybatis(用ImportBeanDefinitionRegister注册) ,activemq,kafak组合式,dubbo,redis等,甚至spring aop也算是bean的注册(用了其他的方式注册进来)扩展,也包括Spring Boot里@SpringBootApplication,springboot也是spring bean的扩展开发,不是吗!!!决定已知性的bean可写死注册,不确定性的最好可配置性组合。搞懂了Spring bean及衍生品(就像金融衍生品一样),就搞懂了90%中国软件开发java领域业务技术的方向

 

参考:

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

你可能感兴趣的:(Spring Bean注册的几种方式)