Read the original text
After reading the official documents of Spring, we can see that Spring basically provides us with three ways to assemble beans:
- Display configuration in XML.
- Display the configuration in Java code.
- Implicit bean discovery mechanism and automatic assembly.
1. Automatic assembly of Bean
Let's first discuss the automatic assembly of beans. To realize the automatic assembly of beans, we need to first understand the two core components of Spring:
- component scanning: Spring will automatically discover the created Bean from the application context.
- Autowrapping: assembling dependencies between individual beans.
Only when these two core components are used together in the development can the automatic assembly of Bean be completed in real sense.
1.1. Create a discoverable Bean
1.1.1. Define a Component Bean through @ Component
public interface CupService { void drink(); } @Component public class CoffeeCupServiceImpl implements CupService { @Override public void drink() { System.out.println("*******Drink coffee*********"); } }
It should be noted that the interface can not be customized here.
<?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 http://www.springframework.org/schema/context/spring-context.xsd"> <!-- Scan module Bean --> <context:component-scan base-package="com.icypt.learn.service"/> </beans>
1.1.3 write test class
public class TestCoffeeCupService { public static ClassPathXmlApplicationContext getCtx() { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml"); return ctx; } @Test public void testDrinkCoffee() { CupService cupService = getCtx().getBean("coffeeCupServiceImpl" , CoffeeCupServiceImpl.class); cupService.drink(); } }
Run test class
22:08:19,273 DEBUG main support.DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory' 22:08:19,277 DEBUG main support.DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor' 22:08:19,279 DEBUG main support.DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor' 22:08:19,302 DEBUG main support.DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'coffeeCupServiceImpl' *******Drink coffee*********
According to the running results, we have completed the method call of component bean. To sum up, when the Spring context (application.xml) is loaded, the bean scanning component will automatically scan and instantiate all the component beans under the "com. Policypt. Learn. Service" package, and finally obtain the instance of the component bean through the getBean() method provided by ClassPathXmlApplicationContext. Method call. I will explain the use of ClassPathXmlApplicationContext in detail in the following learning.
1.2. Name the component Bean
All beans in the Spring application context have a given ID. when we define the component Bean above, we do not define an ID for it, but Spring will specify an ID for it according to the class name. The rule is: change the first letter of the component Bean class name to lowercase.
1.2.1. Manually specify the ID of the component Bean
@Component("milkCup") public class MilkCupServiceImpl implements CupService { @Override public void drink() { System.out.println("*******Drink milk*********"); } }
A component bean with the ID "milkCup" was created.
1.2.2 write test method
@Test public void testDrinkMilk() { CupService cupService = getCtx().getBean("milkCup", MilkCupServiceImpl.class); cupService.drink(); }
Run test method
22:57:35,293 DEBUG main support.DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'coffeeCupServiceImpl' 22:57:35,302 DEBUG main support.DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'milkCup' *******Drink milk*********
From the printed log, we can see that we have successfully specified the ID of "milkCup" for the component Bean.
Spring also supports the @ Named annotation provided in the Java dependency injection specification as an alternative to @ Component. However, the package dependencies to use this annotation to introduce the Java dependency injection specification are as follows:
<dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
1.3. Use @ ComponentScan annotation
@< context: component scan base package = "package name 1, package name 2,..." in ComponentCan and XML display configuration />Configuration items have the same function, which are two different representations of component scanning provided by Spring.
1.3.1. Simple use of @ ComponentScan
@Configuration @ComponentScan public class BaseConfiguration { }
The @ Configuration annotation will be introduced in detail in the following learning. Its main function is to declare this class as a Configuration class of Spring.
1.3.2 write test class
public class TestCupServiceByAnnotationConfig { public AnnotationConfigApplicationContext getAcac() { //Loading Spring application context based on annotation configuration AnnotationConfigApplicationContext acac = new AnnotationConfigApplication Context(BaseConfiguration.class); return acac; } @Test public void testColaService() { ColaCupServiceImpl ccs = getAcac().getBean("colaCupServiceImpl", ColaCupServiceImpl.class); ccs.drink(); } }
The test class of year-on-year 1.1.3 found that after we used @ Configuration, the way to load Spring context also changed.
Run test class
13:52:55,748 DEBUG main support.DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'colaCupServiceImpl' 13:52:55,749 DEBUG main support.DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'milkCup' Disconnected from the target VM, address: '127.0.0.1:51038', transport: 'socket' *********Drink cola***********
It can be found that @ ComponentScan can also scan component beans normally. Its effect is exactly the same as that in XML configuration. However, it should be noted that @ ComponentScan scans all component beans in the package where the configuration class is located by default. How to configure if we want to completely separate the configuration code from the business code in development?
In fact, we just need to configure it as follows:
@ComponentScan(basePackages ={"com.icypt.learn.service"} ) public class BaseConfiguration { }
According to the type of basePackages, we can configure multiple scanning packages, for example:
@ComponentScan(basePackages ={"com.icypt.learn.service","com.icypt.repostiory",...} )
Then through the above configuration, we can put the configuration file under the same package and specify the package name to be scanned through the basePackages attribute of @ ComponentScan.
Maybe sometimes we will encounter such a problem? When the package name of our project is reconstructed for some reason, we need to modify all the scanning paths of all the configuration classes involved, which is very troublesome. In fact, Spring also provides corresponding solutions for this situation:
@Configuration @ComponentScan(basePackageClasses = {MarkBean.class}) public class BasePackageClassesConfig { }
We can create a tag Bean, which has no properties. Its function is to tell ComponentScan its location and guide it to scan all component beans in its directory.
1.4. Use @ Autowired to complete the automatic assembly of Bean
All the above examples are based on a simple Bean component to complete the corresponding functions, but in reality, due to the complexity of its business, it may require coordination and cooperation between the various beans to complete a certain function.
1.4.1. Use @ Autowired
public interface PersonService { void drink(); } @Component public class ManServiceImpl implements PersonService { @Autowired private CupService colaCupServiceImpl; @Autowired private CupService coffeeCupServiceImpl; @Override public void drink() { colaCupServiceImpl.drink();; coffeeCupServiceImpl.drink(); } }
Write test methods
@Test public void testManDrinkService() { PersonService ms = getAcac().getBean("manServiceImpl", ManServiceImpl.class); ms.drink(); }
The operation results are as follows
15:06:20,175 DEBUG main support.DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'manServiceImpl' 15:06:20,199 DEBUG Psupport.DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'markBean' 15:06:20,202 DEBUG main support.DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'milkCup' Disconnected from the target VM, address: '127.0.0.1:53404', transport: 'socket' *********Drink cola*********** *******Drink coffee*********
From the running results, we can see that we have successfully assembled ColaCupServiceImpl and CoffeeCupServiceImpl into ManServiceImpl. The assembly process is as follows: when spinning loads the application context,
@Autowired will find the same BeanID as the property variable from the Bean container for assembly by default, and this kind of assembly is enforced by default. If it cannot find the corresponding BeanID, an exception will be thrown, and the container cannot be loaded successfully. Of course, you can manually set the assembly mechanism to be unenforceable. This will use @ Autowired(required = false). By default, required=true means forced assembly. If it is equal to required = false, Spring will try to assemble. If there is no qualified Bean, it will give up the assembly without affecting the Spring container loading. However, in this case, null judgment must be done at the call of this Bean, otherwise a null pointer exception may be thrown.
1.4.2 usage of @ Autowired
There are three commonly used methods: property, construction method and setter method.
@Component public class ManServiceImpl implements PersonService { @Autowired private CupService colaCupServiceImpl; private CupService coffeeCupServiceImpl; private ShopService smallShopServiceImpl; @Override public void drink() { colaCupServiceImpl.drink();; coffeeCupServiceImpl.drink(); } @Autowired public ManServiceImpl(CupService coffeeCupServiceImpl) { this.coffeeCupServiceImpl = coffeeCupServiceImpl; } @Autowired(required = false) public void setSmallShopServiceImpl(ShopService smallShopServiceImpl) { this.smallShopServiceImpl = smallShopServiceImpl; } }
The effect of these three ways of use is the same. Of course, we can also use other common methods to assemble beans. Similar to @ Component, Java dependency injection specification also provides an annotation to automatically assemble beans. Let's demonstrate.
@Named public class JavaAnnotationManServiceImpl implements PersonService { @Inject private CupService colaCupServiceImpl; private CupService coffeeCupServiceImpl; @Override public void drink() { colaCupServiceImpl.drink();; coffeeCupServiceImpl.drink(); } @Inject public JavaAnnotationManServiceImpl(CupService coffeeCupServiceImpl) { this.coffeeCupServiceImpl = coffeeCupServiceImpl; } }
The above basically covers all the routines of Spring's automatic assembly of beans. Next time, we'll discuss using Java code to assemble beans.
For more recent technology articles, please pay attention to the "freezing point IT" public account