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,java,spring,java)