This is the 16th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

@Configuration+ @Bean injection method

@Configuration is used to declare a Configuration class, and the @Bean annotation is used to declare a Bean and add it to the Spring container.

The specific code is as follows:

@Configuration
public class MyConfiguration {
    @Bean
    public Person person(a) {
        Person person = new Person();
        person.setName("spring");
        returnperson; }}Copy the code

@Componet + @ComponentScan injection mode

Put it on top of the class name, then @ComponentScan on our configuration class, and you can specify a path to scan for beans with @Componet annotations and add them to the container.

@Component
public class Person {
    private String name;

    public String getName(a) {

        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString(a) {
        return "Person{" +
                "name='" + name + '\' ' +
                '} '; }}@ComponentScan(basePackages = "it.chusen.spring.*")
public class Demo1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = newAnnotationConfigApplicationContext(Demo1.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); }}Copy the code

@import Import of annotations

The @import annotation is probably not used much anymore, but is often used when doing Spring extensions with custom annotations and then importing a configuration file into the container. I’m going to talk a little bit more about the @import annotation, but there are three ways it can be used, and I’m going to talk about each of them. This is the source for the @import annotation, which indicates that it can only be placed on a class.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

    /** * to import a class file * {@link Configuration @Configuration}, {@link ImportSelector},
     * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
     */Class<? >[] value(); }Copy the code

@import imports classes directly

public class Person {
    private String name;

    public String getName(a) {

        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString(a) {
        return "Person{" +
                "name='" + name + '\' ' +
                '} '; }}/** * use it directly@ImportImport the Person class and try to fetch the **/ from applicationContext
@Import(Person.class)
public class Demo1 {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = newAnnotationConfigApplicationContext(Demo1.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); }}Copy the code

@Import + ImportSelector

In fact, it’s pretty clear in the @import annotation source code, if you’re interested, we implement an ImportSelector interface, and then we implement the methods in it, and we Import them.

@Import(MyImportSelector.class)
public class Demo1 {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = newAnnotationConfigApplicationContext(Demo1.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); }}class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"it.chusen.spring.model.Person"}; }}Copy the code

I’m going to make a custom MyImportSelector that implements the selectImports method, and then I’m going to put the fully qualified name of the class that we’re importing in there, and it’s really easy to implement.

@Import + ImportBeanDefinitionRegistrar

In this way also need us to achieve ImportBeanDefinitionRegistrar method, specific code is as follows:

@Import(MyImportBeanDefinitionRegistrar.class)
public class Demo1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = newAnnotationConfigApplicationContext(Demo1.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); }}class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // Construct a beanDefinition, which I'll cover later, which can be interpreted as a bean definition.
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Person.class).getBeanDefinition();
        // Register beanDefinition with the Ioc container.
        registry.registerBeanDefinition("person", beanDefinition); }}Copy the code

The implementation above is similar to the second way of Import, in that you need to implement the interface and then Import it. I am introduced to a new concept, BeanDefinition, which can be simply understood as bean definition (bean metadata), which also needs to be managed in IOC container. The metadata of the bean is first provided, and then the applicationContext creates the bean according to the bean metadata.

@Import + DeferredImportSelector

And this way we’re going to have to implement the interface as well, but it’s pretty much the same as the second way of doing @import, DeferredImportSelector, which is a subinterface of ImportSelector, so we’re going to implement it the same way. However, Spring handles this differently, which is related to the automatic import configuration file deferred import in Spring Boot and is very important. The usage is as follows:

@Import(MyDeferredImportSelector.class)
public class Demo1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = newAnnotationConfigApplicationContext(Demo1.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); }}class MyDeferredImportSelector implements DeferredImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // Put the fully qualified name of Person directly
        return newString[]{Person.class.getName()}; }}Copy the code

The @import annotation can be used in the following three ways. Of course, it can also be used with the @Configuration annotation to Import a Configuration class.

Use the FactoryBean interface

The FactoryBean interface and BeanFactory interface should not be confused. The name of a FactoryBean is basically a bean. BeanFactory, as the name implies, is the top interface of the IOC container. Both of these interfaces are important. Code examples:

@Configuration
public class Demo1 {
    @Bean
    public PersonFactoryBean personFactoryBean(a) {
        return new PersonFactoryBean();
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = newAnnotationConfigApplicationContext(Demo1.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); }}class PersonFactoryBean implements FactoryBean<Person> {

    /** * return Person. */
    @Override
    public Person getObject(a) throws Exception {
        return new Person();
    }
    /** * specifies the type of bean to return
    @Override
    publicClass<? > getObjectType() {returnPerson.class; }}Copy the code

In the above code, I added the PersonFactoryBean to the container using @Configuration + @bean. Instead of injecting a Person into the container, I inject the PersonFactoryBean directly and then take the Bean of type Person from the container and run it successfully.

Using BeanDefinitionRegistryPostProcessor

In fact, this is also using the BeanDefinitionRegistry, At the time of the Spring container startup will perform BeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry method, After the beanDefinition has been loaded, the beanDefinition can be postloaded, where the beanDefinition in the IOC container can be adjusted to interfere with the subsequent initialization of the bean.

public class Demo1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        MyBeanDefinitionRegistryPostProcessor beanDefinitionRegistryPostProcessor = newMyBeanDefinitionRegistryPostProcessor(); applicationContext.addBeanFactoryPostProcessor(beanDefinitionRegistryPostProcessor); applicationContext.refresh(); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); }}class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Person.class).getBeanDefinition();
        registry.registerBeanDefinition("person", beanDefinition);
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}}Copy the code

summary

You were introduced to several ways to add beans to the Spring container.

  • @Configuration + @Bean
  • @ComponentScan + @Component
  • @import Implements Import with interfaces
  • Use the FactoryBean.
  • Implement BeanDefinitionRegistryPostProcessor post processing.