6 ways to define beans in Spring (declarative + Programming)

Posted by Sno on Sun, 16 Jan 2022 08:32:54 +0100



Spring's native ways of defining beans can be divided into two categories and six, and we often use only three of one of them.

This is a bit like a Transaction in Spring. We are only familiar with its declarative writing - @ Transaction. We are not familiar with the programmatic writing. Maybe you will say, yes, but it is not necessary. I don't comment here.



Spring defines beans in two ways: declarative and programmatic. As the name suggests, declarative expressions can be understood as using a tag to identify relevant information, and the bottom layer of the code will parse these identifiers; Programming focuses more on using the form of code to deal with relevant logic. The former is more user-friendly and the latter is more underlying.




1, Declarative

1. < \ bean > tag

If we start the Spring container as an xml configuration file, we can use the bean tag to define a bean in the xml configuration file

1) Entity class:

public class MoBian3XML {
}



2)spring-test.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<bean id="mobian3" class="pers.mobian.springseventh.MoBian3XML">
        
</beans>



3) Spring container startup:

public class MainTestXML1 {
	public static void main(String[] args) {

		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-test.xml");
		System.out.println(context.getBean("mobian3"));
	}
}





2. @ Bean annotation

In the configuration class, use the @ Bean annotation.

The @ Configuration annotation should be used on the class. Of course, you don't have to. We just want the Configuration class to have a unique identifier belonging to it

1) Configuration class:

@Configuration
public class Config {

	@Bean(name = "mobian666")
	public MoBian moBian(){
		return new MoBian();
	}
}



2) Spring container startup:

public class MainTest4 {
   public static void main(String[] args) {

      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
      System.out.println(context.getBean("mobian666"));
   }
}





3. @ Component annotation

Different from the scope of < Bean > tags and @ Bean annotations, this method can inject beans into Spring in batches, which are mostly used for classes under controller and service packages. The former is more used for customization of single entity classes.



1) Profile configuration:

1. If the xml file is started, configure it in the xml file

<context:component-scan base-package="pers.mobian.firstTest"/>

2. If it is configured in the configuration class

@Configuration
@ComponentScan("pers.mobian.firstTest")
public class ContextConfig {
}



2) At this time, you need to annotate the class with @ Component and its annotations of the same type (@ Controller, @ Service, @ Repository), so that the class can be injected into the Spring container in the form of Bean.

@Component
public class Car {
}



3) Spring container startup:

public class MoBianTestScan {
   public static void main(String[] args) {

       // Get in the form of configuration file
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
      System.out.println(context.getBean("car"));

       // Get in the form of xml file
      ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-test.xml");
      System.out.println(context.getBean("car"));
   }
}





2, Programming

4. BeanDefinition interface

1) Spring container startup:

public class MainTest1 {
	public static void main(String[] args) {

		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        // Create a beanDefinition and set the bean type of the corresponding beanDefinition object
		AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
		beanDefinition.setBeanClass(MoBian.class);

        // Register beanDefinition in the Spring container and set the name of the corresponding Bean
		context.registerBeanDefinition("mobian",beanDefinition);
		context.refresh();

		System.out.println(context.getBean("mobian"));
	}
}

This method can be started without any configuration files. When we configure beans in a declarative way, the underlying layer is configured in this way




5. FactoryBean interface

1) Create a required class:

public class Car {
}



2) Classes implementing FactoryBean interface:

Implement FactoryBean interface and override getObject and getObjectType methods

public class MoBian2 implements FactoryBean {
	@Override
	public Object getObject() throws Exception {
		return new Car();
	}

	@Override
	public Class<?> getObjectType() {
		return Car.class;
	}
}



3) Spring container startup:

public class MainTest3 {
	public static void main(String[] args) {

		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

		// Here we still define beans programmatically, that is, the fourth way
        // Of course, the Bean can also be defined declaratively here
		AbstractBeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
		definition.setBeanClass(MoBian2.class);
		context.registerBeanDefinition("mobian",definition);


		context.refresh();
		// Gets the object returned by the getObject method
		System.out.println(context.getBean("mobian"));

		// Gets the name of the beanDefinition registered to the Spring container
		System.out.println(context.getBean("&mobian"));
	}
}


Using this method, two Bean objects will be generated, one is generated by the class corresponding to the returned object in the getObject method, and the other is generated by the class that implements the FactoryBean interface. The Bean registered in the Spring container is generated by the class that implements the FactoryBean interface, but when we obtain the Bean of the class that implements the FactoryBean interface, we need to use & + the name when registering the BeanDefinition, and the object returned by the getObject method is obtained by using the name used when registering the BeanDefinition.



Test results of the above example:




6. Supplier interface

1) Spring container startup:

public class MainTest2 {
   public static void main(String[] args) {

      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
      context.registerBean(MoBian.class, new Supplier<MoBian>() {
         @Override
         public MoBian get() {

            return new MoBian();
         }
      });

      context.refresh();
      System.out.println(context.getBean("moBian"));
   }
}

Directly register the Bean of the corresponding type into the Spring container, and the subsequent parameter is a functional interface (that is, this method is not supported until jdk1.8). Directly rewrite its get method to complete the definition of the Bean in the Spring container.