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

    结果:


    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<String, Object> 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<String> 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型。

    灵活性很强,很难达成统一(连交通规矩都难一统,更何况这),条条大路通罗马,没有最好只有合适,如果让你选择注册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

  • 相关阅读:
    guava学习--集合2&Range
    guava学习--集合1
    guava学习--FluentIterable
    guava学习--Supplier Suppliers
    guava--Joiner、Splitter、MapJoinner、MapSplitter
    python_输入一个数,判断是否是素数
    python_33_文件操作2
    python_32_文件操作1
    python_31_集合
    python_输出100:200内的素数
  • 原文地址:https://www.cnblogs.com/dongguangming/p/12792789.html
Copyright © 2020-2023  润新知