Spring's injection methods of Bean

catalog

Registration method

  1. Register via configuration XML
  2. Register with @ Bean
  3. Injection through Beanfactory

Bean to register

/**
 * @Description: Custom Bean
 * @Author: Jonas
 * @Date: 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);
    }
}

Specific implementation

1. Register through configuration XML

applicationContext.xml

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

xml injection is a common way to inject beans into Spring MVC

Now there are more and more Spring Boot projects in the project, and the way to configure XML is relatively cumbersome and difficult to maintain. The following two ways are relatively common at this stage

2. Register through @ Bean

Builder mode creates beans, which will be mentioned later in this class

**
 * @Description: MyBeanBuilder Common builder's 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() {
        return new MyBeanBuilder();
    }

    public MyBean build() {
        return new MyBean(this.name,this.age);
    }


}

Create Spring objects with @ Bean

/**
 * @Description: Create and inject Spring with @ Bean
 * @Author: Jonas
 * @Date: 2020-06-01 23:09
 */
@Configuration
@Slf4j
public class AnnotationBean {

    // Call the constructor through @ Bean, generate the Bean, and submit the Bean to BeanFactory for management
    @Bean
    public MyBean myBean() {
        MyBean myBean = new MyBean("hello", 10);
        log.info("towards spring Successful injection myBean");
        return myBean;
    }

    // Call the build method through @ Bean to generate the Bean, which is essentially the same as the above method
    @Bean
    public MyBean myBean2() {
        MyBean tom = MyBeanBuilder.getInstance()
                .withName("Tom")
                .withAge(22)
                .build();
        log.info("towards spring Successful injection myBean2");
        return tom;
    }
}

In fact, both are created by calling the constructor, but the latter indirectly passes parameters to the constructor

2. Dynamic injection through Beanfactory

/**
 * @Description: Custom Bean factory
 * @Author: Jonas
 * @Date: 2020-06-01 22:50
 */
@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 creation Bean");
        log.info("Output the third parameter===>{}",string);
        return new MyBean(name,age);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // Dynamically generate beans through DefaultListableBeanFactory
        DefaultListableBeanFactory capableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        log.info("==================Access method====================");
        // Dynamically create 10 different Bean objects of MyBean type
        for (int i=0;i<10;i++) {
            // Call constructor to create dynamically
            // registerBean(applicationContext,"dynamic"+i,MyBean.class,"Bean"+i,10+i);
            // Call factory method to create Bean dynamically
            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<T> 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 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, not a subclass of another class
                //.rootBeanDefinition()
                // To build a subclass Bean, you must pass the name of a parent Bean, not the parent of another class
                // .childBeanDefinition()
                // Build a standard Bean
                .genericBeanDefinition()
                // Set factory method and factory class
                .setFactoryMethodOnBean(factoryMethod, factoryBeanClazz);
        for (Object arg: args) {
            // Set factory method parameters
            beanDefinitionBuilder.addConstructorArgValue(arg);
        }
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        beanFactory.registerBeanDefinition(registerName,beanDefinition);

        return (T) applicationContext.getBean(registerName);
    }
}

Call the factory method createBean to dynamically create 10 different beans

Call constructor to dynamically create 10 different beans

summary

These three kinds of registration methods are commonly used by Bean. The first one is common in Spring MVC, but it is not very convenient. The second is the Bean registration method commonly used in Spring Boot, which usually needs to be loaded into Spring manually in configuration classes. The third method is often used to create a batch of beans of the same type with certain repetitive naming rules, such as Swagger's dynamic grouping in the previous period

appendix

Create Swagger groups dynamically

EnableModuleTag.java

/**
 * @Description: Automatic setting of module tag is convenient for automatic writing of log module and grouping management of swagger UI
 * @author: Jonas
 * @since: 2020/5/29 14:52
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableModuleTag {

    String moduleName() default "SYSTEM";

}

SwaggerConfig.java

/**
 * @Description: swagger-ui Configuration, single application automatically creates swagger UI grouping
 * @author: Jonas
 * @since: 2020/5/30 22:53
 */
@Configuration
@EnableSwagger2
@Slf4j
public class SwaggerConfig implements InitializingBean {

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

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public Docket docket() {
        // basePackage needs to scan the path of the annotation to generate the document
        return new Docket(DocumentationType.SWAGGER_2)
                // Group names start with aaa to be at the top
                .groupName("Default grouping(whole)")
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.jonas.data"))
                .paths(PathSelectors.any())
                .build();
    }

    //Basic information, page display
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("SwaggerAPI")
                .description("xxxx Project interface api")
                //Version No
                .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 will enter here to judge and classify into different groups,
                    // **Please do not change the order of the following two pieces of code. The annotation on the method has priority**
                    // The module name is marked on the method
                    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 labeled?
                    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 a dock bean
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        // Each variable defined in ApiConstantVersion will become a ticket
        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 the set
            String moduleName = annotation.moduleName();
            groupName.add(moduleName);
            // Dynamic injection bean
            AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
//            if (autowireCapableBeanFactory instanceof DefaultListableBeanFactory) {
                DefaultListableBeanFactory capableBeanFactory = (DefaultListableBeanFactory) autowireCapableBeanFactory;
                    // Note that "factory name and method name" means to create a socket with the specified method of this bean
                // Get 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:{} reach Spring in",registerName);
//            }
        }

    }
}

Usage:
controller annotated

At startup, different beans are automatically registered into Spring, so that different groups can be created automatically according to modules, which is convenient for API management

Tags: Spring xml Java socket

Posted on Fri, 05 Jun 2020 22:14:16 -0700 by Grant Holmes