Registration way

  1. By configuring XML registration
  2. Register via @bean
  3. Injection via Beanfactory

Beans that need to be registered

/ * * *@Description: Custom Bean *@Author: Jonas
 * @Date: the 2020-06-01 22:52 * /
@Data
@Slf4j
public class MyBean {

    private String name;

    private int age;

    public MyBean(String name, int age) {
        this.name = name;
        this.age = age;
        log.info(Call constructor to create Bean, name={},age={},name,age); }}Copy the code

The specific implementation

1. Configure XML registration

applicationContext.xml

<bean id="myBean" class="com.jonas.config.bean.MyBean" >
    <constructor-arg name="name" value="Jonas"/>
    <constructor-arg name="age" value="18"/>
</bean>
Copy the code

XML injection is a common way to inject beans in Spring MVC

With more and more Spring Boot projects in the works, and the XML configuration method still relatively cumbersome and difficult to maintain, the following two methods are relatively common at this stage

2. Register with @bean

The Builder pattern creates beans, as described later in this class

* * *@Description: MyBeanBuilder common builder methods *@Author: Jonas
 * @Date: 2020-06-01 22:57* /public class MyBeanBuilder {

    private String name;

    private int age;

    public MyBeanBuilder withName(String name) {
        this.name = name;
        return this;
    }

    public MyBeanBuilder withAge(int age) {
        this.age = age;
        return this;
    }

    public static MyBeanBuilder getInstance(a) {
        return new MyBeanBuilder();
    }

    public MyBean build(a) {
        return new MyBean(this.name,this.age); }}Copy the code

Create a Spring object via @bean

/ * * *@DescriptionUse:@BeanCreate and inject Spring *@Author: Jonas
 * @Date: the 2020-06-01 23:09 * /
@Configuration
@Slf4j
public class AnnotationBean {

    // The constructor is called through @bean to generate the Bean and put it into the BeanFactory management
    @Bean
    public MyBean myBean(a) {
        MyBean myBean = new MyBean("hello".10);
        log.info("Successfully injected myBean into Spring");
        return myBean;
    }

    // Call the build method via @bean to generate the Bean, essentially the same way as above
    @Bean
    public MyBean myBean2(a) {
        MyBean tom = MyBeanBuilder.getInstance()
                .withName("Tom")
                .withAge(22)
                .build();
        log.info("Successfully injected myBean2 into Spring");
        returntom; }}Copy the code

Both are essentially created by calling the constructor, but the latter indirectly passes arguments to the constructor

2. Use Beanfactory for dynamic injection

/ * * *@Description: Custom Bean factory *@Author: Jonas
 * @Date: the 2020-06-01 o * /
@Configuration
@Slf4j
public class MyBeanFactory implements InitializingBean {

    @Autowired
    private ApplicationContext applicationContext; // Spring context

    public MyBean createBean(String name,int age,String string) {
        log.info("Call factory method to create Bean");
        log.info("Print the third argument ===>{}",string);
        return new MyBean(name,age);
    }

    @Override
    public void afterPropertiesSet(a) throws Exception {
        / / by DefaultListableBeanFactory dynamically generated Bean
        DefaultListableBeanFactory capableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        log.info("================== Access method ====================");
        // Dynamically create 10 different Bean objects of type MyBean
        for (int i=0; i<10; i++) {// Call the constructor to create it dynamically
            // registerBean(applicationContext,"dynamic"+i,MyBean.class,"Bean"+i,10+i);
            // Call the factory method to dynamically create the Bean
            registerBean(applicationContext,"dynamic"+i,
                    "myBeanFactory"."createBean"."Bean" + i,20+i, UUID.randomUUID().toString()); }}/** * Call the Bean constructor to register the Bean into the context *@param applicationContext
     * @param registerName
     * @param clazz
     * @param args
     * @param <T>
     * @return* /
    private <T> T registerBean(ApplicationContext applicationContext, String registerName, Class
       
         clazz, Object... args)
        {
        if(applicationContext.containsBean(registerName)) {
            Object bean = applicationContext.getBean(registerName);
            if (bean.getClass().isAssignableFrom(clazz)) {
                return (T) bean;
            } else {
                throw new RuntimeException("BeanName repeat" + registerName);
            }
        }
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
        for (Object arg : args) {
            // Set the constructor parameters
            beanDefinitionBuilder.addConstructorArgValue(arg);
        }
        BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();

        BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
        beanFactory.registerBeanDefinition(registerName, beanDefinition);
        return applicationContext.getBean(registerName, clazz);
    }

    /** * Call the factory method to register the Bean into the context *@param applicationContext
     * @param registerName
     * @param factoryBeanClazz
     * @param factoryMethod
     * @param args
     * @param <T>
     * @return* /
    private <T> T registerBean(ApplicationContext applicationContext,String registerName, String factoryBeanClazz,String factoryMethod,Object... args) {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
                // Build a Bean of a parent class
                //.rootBeanDefinition()
                // To build a subclass Bean, you must pass the name of the Bean's parent class
                // .childBeanDefinition()
                // Build a standard Bean
                .genericBeanDefinition()
                // Set the factory method and factory class
                .setFactoryMethodOnBean(factoryMethod, factoryBeanClazz);
        for (Object arg: args) {
            // Set the factory method parameters
            beanDefinitionBuilder.addConstructorArgValue(arg);
        }
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        beanFactory.registerBeanDefinition(registerName,beanDefinition);

        return(T) applicationContext.getBean(registerName); }}Copy the code

Call the factory method createBean to dynamically create 10 different beans

Call the constructor to dynamically create 10 different beans

conclusion

These three are common ways to register beans. The first one is more common in SpringMVC, but feels less convenient. The second is the Bean registration method commonly used in Spring Boot, which often requires manual loading of beans into Spring in configuration classes. The third type is often used when you need to create a batch of beans of the same type that have a certain repeating naming convention, as we did a while ago when we dynamically grouped Swagger

The appendix

Dynamically create Swagger groups

EnableModuleTag.java

/ * * *@Description: Automatic setting of module markers facilitates automatic writing of log modules and group management of swagger-UI *@author: Jonas
 * @since: 2020/5/29 any valiant man * /
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableModuleTag {

    String moduleName(a) default "SYSTEM";

}

Copy the code

SwaggerConfig.java

/ * * *@Description: Swagger-UI configuration, single application automatically creates swagger-UI groups *@author: Jonas
 * @since: 2020/5/30 so * /
@Configuration
@EnableSwagger2
@Slf4j
public class SwaggerConfig implements InitializingBean {

    private Set<String> groupName = new HashSet<>();

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public Docket docket(a) {
        // basePackage needs to scan the path of the annotations to generate the document
        return new Docket(DocumentationType.SWAGGER_2)
                // Group names start with AAA so that they are first in line
                .groupName("Default group (all)")
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.jonas.data"))
                .paths(PathSelectors.any())
                .build();
    }

    // Basic information, page display
    private ApiInfo apiInfo(a) {
        return new ApiInfoBuilder()
                .title("SwaggerAPI")
                .description(XXXX project interface API)
                / / version number
                .version("1.0.0")
                .build();
    }

    private Docket buildDocket(String groupName) {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .groupName(groupName)
                .select()
                .apis(method -> {
                    // Each method comes in here to judge and categorize into different groups,
                    // ** Please do not switch the order of the following two pieces of code, annotations on methods have priority **
                    // This method is labeled with the module name
                    if (method.isAnnotatedWith(EnableModuleTag.class)) {
                        EnableModuleTag annotation = method.getHandlerMethod().getMethodAnnotation(EnableModuleTag.class);
                        if(annotation.moduleName() ! =null&& annotation.moduleName().length() ! =0) {
                            if (Arrays.asList(annotation.moduleName()).contains(groupName)) {
                                return true; }}}// Is the class of the method marked?
                    EnableModuleTag annotationOnClass = method.getHandlerMethod().getBeanType().getAnnotation(EnableModuleTag.class);
                    if(annotationOnClass ! =null) {
                        if(annotationOnClass.moduleName() ! =null&& annotationOnClass.moduleName().length() ! =0) {
                            if (Arrays.asList(annotationOnClass.moduleName()).contains(groupName)) {
                                return true; }}}return false;
                })
                .paths(PathSelectors.any())
                .build();
    }

    /** * dynamically create the Docket bean *@throws Exception
     */
    @Override
    public void afterPropertiesSet(a) throws Exception {
        // Each variable defined in ApiConstantVersion becomes a docket
        Map<String, Object> beanMap = applicationContext.getBeansWithAnnotation(EnableModuleTag.class);
        for (Iterator<Object> iterator = beanMap.values().iterator(); iterator.hasNext();) {
            Object bean = iterator.next();
            EnableModuleTag annotation = bean.getClass().getAnnotation(EnableModuleTag.class);
            // Get the module name and place it in set
            String moduleName = annotation.moduleName();
            groupName.add(moduleName);
            // Dynamically inject beans
            AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
// if (autowireCapableBeanFactory instanceof DefaultListableBeanFactory) {
                DefaultListableBeanFactory capableBeanFactory = (DefaultListableBeanFactory) autowireCapableBeanFactory;
                    // Note the "factory name and method name", which means the specified method of this bean is used to create the docket
                // Get the hump name
                String registerName = CommonUtils.getHumnName("swagger_config_"+moduleName);
                AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
                        .genericBeanDefinition()
                        .setFactoryMethodOnBean("buildDocket"."swaggerConfig")
                        .addConstructorArgValue(moduleName)
                        .getBeanDefinition();
                capableBeanFactory.registerBeanDefinition(registerName, beanDefinition);
                log.info("Register Bean:{} into Spring",registerName);
/ /}}}}Copy the code

Usage: Controller annotated

Different beans are automatically registered into Spring at startup, allowing for the automatic creation of different groupings by module and easy API management