Spring (18) - configure beans in the form of Java classes

18 Configure bean definitions in the form of Java classes

In addition to the traditional use of XML to configure the underlying bean container definition, Spring also supports configuration in the form of familiar Java classes. When configuring in the form of a Java class, we will use a Java class as the main body of the configuration, and mark the class with @Configuration, indicating that it is a configuration class. Then define the corresponding bean definition as a public method in the Java configuration class, and mark the method with @Bean, indicating that it is a bean definition. The return type corresponding to the method annotated with @Bean is the Class type corresponding to the generated bean definition, the corresponding method body implementation is the process we use to generate an instance of the corresponding bean definition, and the corresponding method name is the default beanName of the bean definition. Let's take a brief look at a corresponding implementation first.

@Configuration
public class SpringConfig {

	@Bean
	public Hello hello() {
		return new Hello();
	}
	
}

In the above code, we marked our class SpringConfig as a Spring configuration class through @Configuration, and then defined a method annotated with @Bean, which Spring will add to the bean container as a bean definition, The corresponding beanName is "hello", and then directly new a corresponding instance as the instance of the bean definition. After that, we can obtain the corresponding bean definition from the bean container generated by the configuration class. The corresponding test code can be as follows.

@ContextConfiguration(classes={SpringConfig.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class ConfigurationTest {
	
	@Autowired
	private ApplicationContext context;
	
	@Test
	public void test() {
		System.out.println(context.getBean("hello", Hello.class));
	}

}

18.1 @Bean

When using Java class-based configuration, we can use @Bean to annotate the method in the configuration class that needs to be defined as a bean definition in the bean container. After the annotation, the name of the method is used as the beanName of the corresponding bean definition by default, and the return type of the method is used as the Class type of the corresponding bean definition.

@Configuration
public class SpringConfig {

	@Bean
	public Hello hello() {
		return new Hello();
	}
	
}

In the above example, we use the @Bean annotation to define a bean definition in the Java class-based configuration, which is equivalent to the following definition in our XML configuration file.

<bean id="hello" class="com.app.Hello"/>

18.1.1 Designated beanName

By default, Spring will use the method name as the beanName of the corresponding bean definition. If the user wants to specify the beanName of the corresponding bean definition, it can be specified through the name attribute of @Bean.

@Bean(name="hello1")
public Hello hello() {
	return new Hello();
}

We can also specify multiple names for the bean definition through the name attribute of @Bean. At this time, the name attribute can be specified in the form of an array. In the following example, we mean to specify the beanName as "hello" and "hello1" at the same time.

@Bean(name={"hello", "hello1"})
public Hello hello() {
	return new Hello();
}

18.1.2 Specifying Lifecycle Callback Methods

According to the introduction of the previous article, we know that the bean's lifecycle callback method can be specified in three ways, using the JSR-250 standard @PostConstruct and @PreDestroy for annotation, implementing the InitializationBean and DisposableBean interfaces, and defining the init-method and destroy through the bean -method to specify. For the first two methods, beans configured with @Bean can also be called back like other beans configured based on annotations or based on XML. For the third method, we need to specify it through the initMethod and destroyMethod attributes of @Bean, and the corresponding attribute value represents the corresponding callback method name.

	@Bean(initMethod="init", destroyMethod="destroy")
	public Hello hello() {
		return new Hello();
	}

In the above example, we specify the initialization callback method of bean hello as init() through the initMethod attribute, and specify the corresponding pre-destruction callback method as destroy() through the destroyMethod attribute. It is equivalent to the following form of our XML-based configuration.

<bean id="hello" class="com.app.Hello" init-method="init" destroy-method="destroy"/>

18.1.3 Specify whether to inject automatically

When using XML for configuration, we can specify whether automatic injection is required through its autowire. Correspondingly, we can use the autowire attribute on @Bean to specify whether to perform automatic injection. Available values ​​are Autowire.NO, Autowire.BY_NAME, and Autowire.BY_TYPE. The default is Autowire.NO, which means no automatic injection. Autowire.BY_NAME means automatic injection by name, Autowire.BY_TYPE means automatic injection by type.

	@Bean(autowire=Autowire.BY_TYPE)
	public Hello hello() {
		return new Hello();
	}

The above example represents automatic injection of dependent beans by type. It is equivalent to the following XML definition.

<bean id="hello" class="com.app.Hello" autowire="byType"/>

18.1.4 Specifying a Scope

The Scope corresponding to the bean defined by @Bean is also singleton by default. If users want to change this default strategy, they need to use the @Scope annotation to define the method corresponding to @Bean. The specific usage is the same as the one we introduced earlier. It's the same when configuring a bean definition. The following means that we define the corresponding Scope as prototype.

	@Bean
	@Scope("prototype")
	public Hello hello() {
		return new Hello();
	}

If you need to be proxied, you can specify proxyMode.

	@Bean
	@Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
	public Hello hello() {
		return new Hello();
	}

18.1.5 Dependency Injection

For bean injection in the same configuration class annotated with @Configuration, we can directly obtain the corresponding bean instance for injection in the form of method invocation. In the following example, we obtain a World instance by calling the world() method, and then inject it into the Hello instance.

	@Bean
	public Hello hello() {
		Hello hello = new Hello();
		hello.setWorld(this.world());
		return hello;
	}
	
	@Bean
	public World world() {
		return new World();
	}

You can also use the @Autowired or @Inject annotation for automatic injection as described earlier, that is, define it in the Class class corresponding to the corresponding bean. In the following example, we define that the world needs to be injected automatically through @Autowired. For configuration using Java classes, Spring will automatically scan the corresponding annotation to complete the corresponding bean definition.

public  class  Hello {
	
	@Autowired
	private World world;

}

Let's look at another example. In the following example, we call the world() method twice to obtain the corresponding bean instance and inject hello and beanA respectively. Because the bean instance generated by Spring by default is of singleton type, in order to realize this mechanism, after the first instance is generated by calling world() for the first time, Spring will cache the corresponding object and call world next time. When the () method gets an instance, it directly gets the cached instance. So for the following situation, in fact, Spring will only generate one World instance. Spring's singleton bean mechanism based on Java class configuration is implemented by dynamically generating classes through CGLIB. When the system starts, Spring will build all subclasses of Class marked with @Configuration through CGLIB, and call the parent class in the subclass. Before the corresponding method of the class generates the corresponding bean instance, it will be obtained from the cache of the subclass first. Only when it cannot be obtained, will the parent class be called to generate a new instance. After the corresponding instance is generated, it will be cached to the corresponding instance. in the cache. In addition, in view of this mechanism of Spring, our corresponding Java configuration class is not final, and there is a no-argument constructor.

@Configuration
public class SpringConfig {

	@Bean
	public Hello hello() {
		Hello hello = new Hello();
		hello.setWorld(world());
		return hello;
	}
	
	@Bean
	public World world() {
		return new World();
	}
	
	@Bean
	public BeanA beanA() {
		BeanA beanA = new BeanA();
		beanA.setWorld(world());
		return beanA;
	}
	
}

18.1.6 Using the lookup-method

When we introduced XML configuration before, we used lookup-method to solve the problem of singleton bean referencing multiple beans. When using Java-based configuration, if we also want to solve the situation of singleton bean referencing multiple beans in this way, we can solve it in the following way. For example, we have a singleton bean, corresponding to the class Hello, which needs to refer to a multi-instance bean World, then we can define a public method in Hello to get the World instance, and then every time we need to use the World instance, Obtained through this method, the following getWorld() method is this function.

public  class  Hello {
	
	public void doSomething() {
		World world = this.getWorld();
		System.out.println(world);
		//...
	}
	
	public World getWorld() {
		return null;
	}

}

Then when we define the singleton bean corresponding to Hello, we can create a new subclass of the anonymous Hello class, and then rewrite the getWorld() method in it. The corresponding method body is obtained through the corresponding method of the configuration class marked with @Configuration. Multiple instances of World instances. In this way, every time we call the getWorld() method in the hello of the singleton, a brand new World instance will be obtained from the bean container.

 

@Configuration
public class SpringConfig {

	@Bean
	public Hello hello() {
		Hello hello = new Hello() {
			public World getWorld() {
				return world();
			}
		};
		return hello;
	}
	
	@Bean
	@Scope("prototype")
	public World world() {
		return new World();
	}
	
}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326295144&siteId=291194637