Several ways to register Spring Bean

Keywords: Java Spring Mybatis Dubbo

All roads lead to dragons and horses

Premise: please https://blog.csdn.net/dong19891210/article/details/105697175 In case of

Spring bean s can be registered in the following ways:

1. Register through GenericBeanDefinition

Example code:

Message helper class

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("The message is: " + message);
	}
}

Register test class:

/**
 * 
 * @author dgm
 * @describe "GenericBeanDefinition Register bean definition“
 * @date 2020 April 27, 2006
 */
public class GenericBeanDefinitionExample {

	public static void main (String[] args) {
	      DefaultListableBeanFactory context =
	                new DefaultListableBeanFactory();

          //Construct the bean definition here
	      GenericBeanDefinition gbd = new GenericBeanDefinition();
	      gbd.setBeanClass(Message.class);
          
          //
	      MutablePropertyValues mpv = new MutablePropertyValues();
	      mpv.add("message", "this is a bean");

          //Register to environment context
	      context.registerBeanDefinition("myBean", gbd);

	      Message bean = context.getBean(Message.class);
	      bean.print();
	      Message myBean = (Message) context.getBean("myBean");
	      myBean.print();
	  }
}

result:


2. Register through BeanDefinitionBuilder

/**
 * 
 * @author dgm
 * @describe ""
 * @date 2020 April 16, 2016
 */
public class BeanDefinitionBuilderExample {
	 public static void main (String[] args) {
	      DefaultListableBeanFactory context =
	                new DefaultListableBeanFactory();

          //Using the builder pattern
	      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();
	  }
}

The effect is the same as that in the first case, except for the bean definition builder mode

3. Through 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 class

@Configuration
public class MyConfig {
  @Bean
  MessageBeanFactoryPostProcessor messageConfigBean () {
      return new MessageBeanFactoryPostProcessor();
  }
}

Test class:

/**
 * 
 * @author dgm
 * @describe "Test BeanFactoryPostProcessor“
 * @date 2020 April 27, 2006
 */
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();
	  }
}

effect:


4. Through 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 class

@Configuration
public class MyConfig {
  @Bean
  ConfigBeanFactoryPostProcessor myConfigBean () {
      return new ConfigBeanFactoryPostProcessor();
  }
  
  /*@Bean
  MessageBeanFactoryPostProcessor messageBeanFactoryPostProcessor () {
      return new MessageBeanFactoryPostProcessor();
  }*/
  
  @Bean
  MessageBeanDefinitionRegistryPostProcessor messageBeanDefinitionRegistryPostProcessor () {
      return new MessageBeanDefinitionRegistryPostProcessor();
  }
}

Test class:

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

effect:


 

5. Through Import

The import types are as follows:

5.1 ImportSelector import

public interface PrintService {

	void print(String msg);
}

public class PrintServiceImpl  implements PrintService{

	@Override
	public void print(String msg) {
		System.out.println("Hello : " + msg);
	}
}

//Focus on the implementation of ImportSelector 
public class MessageImportSelector implements ImportSelector {

	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		// TODO Auto-generated method stub
        return new String[] {PrintServiceImpl.class.getName()};

	}

}

//Configuration class
@Configuration
@Import(MessageImportSelector.class)
public class MessageImportSelectorConfiguration {

}

Test code and effect:

 

Note: I'm using demo (selectImports() is dead). In the actual scenario, bean s can be injected dynamically, with a large imagination space.

5.2 ImportBeanDefinitionRegistrar registration

/**
 * 
 * @author dgm
 * @describe "Implement importbeandefinitionregister“
 * @date 2020 April 28, 2006
 */
public class MessageImportBeanDefinitionRegistrar implements
		ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata,
			BeanDefinitionRegistry registry) {
		// Just take the demonstration as an example. In the real scenario, dynamic data is obtained through importing classmetadata
		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 class:

@Configuration
@Import(MessageImportBeanDefinitionRegistrar.class)
public class MessageImportBeanDefinitionRegistrarConfiguration {

}

Testing

/**
 * 
 * @author dgm
 * @describe "Test importbeandefinitionregister“
 * @date 2020 April 28, 2006
 */
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 combination, such as kafak integration into spring

/**
 * 
 * @author dgm
 * @describe "Implements the import of the ImportSelector interface“
 * @date 2020 April 28, 2006
 */
public class MessageImportSelector implements ImportSelector {

	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		// TODO Auto-generated method stub
        //return new String[] {PrintServiceImpl.class.getName()};
		//Don't write anymore. Use the metadata
		Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(PrintServiceScan.class.getName());
        String[] basePackages = (String[]) annotationAttributes.get("basePackages");
        if (basePackages == null || basePackages.length == 0) {//basePackages of PrintServiceScan is an empty array by default
            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 April 28, 2006
 */
@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 {

}

Final test:

/**
 * 
 * @author dgm
 * @describe "Test the combined ImportSelector“
 * @date 2020 April 28, 2006
 */
public class ImportSelectorDemo {

	public static void main(String[] args) {
		 AnnotationConfigApplicationContext applicationContext =
		new AnnotationConfigApplicationContext(MessageImportSelectorConfiguration.class);
		 PrintService ps = (PrintService) applicationContext.getBean(PrintService.class);
	     ps.print("Combined type ImportSelector demo");
	    }
}

 

For details, please refer to the source ConfigurationClassParser class to handle different import s


 

Summary: I write step by step. There are several ways to register spring bean s: generic bean definition, bean definition Builder (design patterns are everywhere), bean factory postprocessor, bean definition registry postprocessor, Import type.

It's very flexible and difficult to achieve unification (even the traffic rules are difficult to be unified, let alone this). All roads lead to a long road. There's no best way but to be suitable. If you choose to register beans or develop or integrate with the third party, you can refer to mybatis (register with import bean definition register), activemq, kafak combination, dubbo, redis, etc., or even SPR spring aop is also an extension of bean registration (registered in other ways), including @ EnableAutoConfiguration in Spring Boot. Spring Boot is also an extension development of spring bean s, isn't it!!! The beans that determine the known properties are writable and registered, and the best configurable combination of uncertainties.

 

reference resources:

0. https://www.programcreek.com/java-api-examples/index.php?class=org.springframework.beans.factory.support.GenericBeanDefinition&method=setAttribute

1. bean definition for automatic FilterRegistrationBeanFactory http://dimafeng.com/2015/11/27/dynamic-bean-definition/

2. Using @ import import to implement the class of the importbeandefinitionregister interface https://blog.51cto.com/14672031/2474904

3. Spring registers Bean's advanced application with container https://cloud.tencent.com/developer/article/1497795

4. How to integrate Jdon Framework with Spring http://en.jdon.com/springIntegration.html

Posted by mahaguru on Mon, 27 Apr 2020 21:21:30 -0700