(3) automated assembly bean - Spring retrospective study

Author: Chen Buyi
www.cnblogs.com/chenbenbuyi

Spring series of articles
(1) a thorough understanding of the Spring container and application contexts --Spring review learning
(2) DI / IOC and AOP principle acquaintance --Spring review learning
(3) automated assembly bean - Spring retrospective study
(4) through Java annotations and XML configuration assembly bean - Spring retrospective study
(5) AOP programming --Spring review section to learn learning --Spring review

  Bowen said when speaking on the Spring IOC container, although the container is powerful, but the container itself is just an empty shell, we need to take the initiative to put the assembly object and tell it collaborative relationships between objects, the container can then follow our instructions to play it's magic, bean complete the assembly of the mission. Here, we conduct Spring create collaborative relationships between application objects to be assembled. Spring provides a lot of assembly bean way for us to choose in development, we used to have three assembly mechanism: automatic assembly, Java annotations and XML configuration. We will first generally called implicit assembly mechanism, the latter two mechanisms to fit the display. Practical applications, based on considerations of convenience, choice is certainly implicit automated assembly mechanism, only when the need to inject the bean source code is not maintained by its own program, but the introduction of third-party application components when we come to consider display fitting manner bean. Of course, various ways can be assembled with freedom of choice in the actual application, the encoding process which is also not rigidly stick, applicable like. This blog first to tell --bean implicit mechanism assembly automated assembly.

  Are you curious about is how to achieve its Spring automated assembly mechanism, in fact, Spring primarily through the following two aspects:

  • Scanning assembly - assembly by opening Spring scan function allows to automatically discover application context of the bean;
  • Automatic assembly - automatically satisfy the dependencies between components.

  Below, we look at how Spring separately by component scans and automatic assembly to automated assembly applications for our bean. We first define a bus interface:

package spring.facade;
 
public interface Car {
    void drive();
}

Component scans

  The essence of that component scans through the scanning control, make Spring automatically discover application bean. But so many objects in the program, Spring how it needs to know what the object is created to manage it? This involves a component of Spring comment - @ Component, component class is marked is the class of the annotation of Spring, Spring container loading process will automatically create bean (PS for the class: Spring is actually a component according to notes semantic classification there @Controller @Repository @Service etc., are applied to the control layer, persistence layer and business layer, here are only examples demonstrate, no distinction explain). So, we can implement the interface of a comment on the label, indicating implementation class is to be created instance of Spring -

 package spring.impl;
 
 import org.springframework.stereotype.Component;
 import spring.facade.Car;
 
 @Component
 public class QQCar implements Car {
     @Override
     public void drive() {
        System.out.println("开QQ车");
     }
}

  However, Spring's annotation scanning is not turned on by default, so we need to show the configuration annotations begin. Here, too, there are two ways, Java annotations and XML way, we are showing out:

Java configuration class CarConfig:

package spring.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@ComponentScan
public class CarConfig {
}

XML configuration file applicationContext.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 
       http://www.springframework.org/schema/context/spring-context.xsd">
    
    <!--启动注解扫描-->
    <context:component-scan base-package="spring"/>
</beans>

  Next we write the test class to see if Spring is not automatic to discover our annotated bean components and objects created for us:

package spring.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import spring.config.CarConfig;
import spring.impl.QQCar;
import static org.junit.Assert.assertNotNull;

/**
 * 注解释义:
 * @RunWith(SpringJUnit4ClassRunner.class)  测试在Spring环境中运行
 * @ContextConfiguration  上下文配置注解,指定配置文件(Java类或XML文件)的位置
 */
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(classes = CarConfig.class) //加载Java配置类的方式
@ContextConfiguration(locations = "classpath:resource/applicationContext.xml") //加载XML配置的方式
public class CarTest {
    @Autowired
    private QQCar car ;

    @Test
    public void carTest(){
        assertNotNull(car);
    }
}

  Although the programming trend is the increasing use of Java annotations way, but you will find the above test, by way of XML annotations can test success, and Java annotations way it is a failure, the test will throw NoSuchBeanDefinitionException abnormal, indicating that no component definition QQCar, that is Spring did not find it, Why? the reason is very simple, that is to start the next pack of Java annotations based on the way notes can only scan default scan configuration where the class and its sub-package of If you want to clear the scan other components of the package, indicating the need to display in the annotation @ComponetScan start scanned, as changed @ComponentScan ( "spring.impl"), an appeal will be able to pass the test. If there are a plurality of packages to be scanned, may be configured such that: @ComponentScan (basePackages = { "spring.impl", "spring.test"}), but such representation is a character string type unsafe, and write die package name is disadvantageous for refactoring, we can specify a class or interface packet included in the packet to specify the scan, can then be marked as such: @ComponentScan (basePackageClasses = QQCar.class), a plurality of packages can also be used in {} An array form. But this is still unfriendly to the reconstruction, the best way is to define a standard interface to scan empty package, the interface is only used to specify packet scanning range, so the impact will be reconstructed to a minimum.

Automated assembly

  The foregoing describes only how to clarify the definition of a class as a Spring components Spring components and start scanning, and we have demonstrated through testing, Spring does scanning to the component class we specify and create an object for us. However, objects created only independent existence, and no dependence collaboration and other objects; practical application, dependent on collaboration between objects is another common, however, and while the object you want to create for our Spring components by scanning the actual business establish mutual dependence collaboration requires the use of automatic assembly Spring. For demonstration purposes, we'll define a class Man, Man's job is to drive a car, let injected through the constructor way to satisfy dependencies to see if Spring will give us what we need to automatically inject Car instance of an object -

package spring.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import spring.facade.Car;

@Component
public class Man {
    
    private Car car;

    public Man() {
    }

    @Autowired
    public Man(QQCar car) {
        this.car = car;
    }

    public void work() {
        car.drive();
    }
}

Test Methods

 package spring.test;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 import spring.config.CarConfig;
 import spring.impl.Man;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CarConfig.class)
public class CarTest {

    @Autowired
    Man man;

    @Test
    public void carTest() {
        man.work();
    }
}

  As the above code, test course was successful in test class, Man as a component class is Spring scan and create an object instance that calls the work method when the need to instantiate an object Car, and our argument constructor in there shows the dependence on the object by @Autowired notes, the program is running, Spring will automatically inject instance object Car for us to meet the target dependent, and this is where the essence of automatic assembly. In fact, not only the structure can be used @Autowired annotation in the method attribute Setter, even conventional methods, can be used to satisfy the dependency between @Autowired annotation objects, features automatic injection -

 package spring.impl;
 
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import spring.facade.Car;
 
 @Component
 public class Man {
    private Car car;

    public Man() {
    }
    //构造器实现自动装配
    //    @Autowired
    public Man(QQCar car) {
        this.car = car;
    }

    //Setter方法实现自动装配
    // @Autowired
    public void setCar(QQCar car) {
        this.car = car;
    }
    //普通方法实现自动装配
    @Autowired
    public void insertCar(QQCar car) {
        this.car = car;
    }

    public void work() {
        car.drive();
    }
}

  We will add a different method to test Man class, it can still be successful. But one thing to note, when a non-constructor for automatic assembly, although we do not own new objects, but Spring will create an instance of Man by the default constructor, then the Man class if there are parameters defined in the constructor, We must give the default constructor constructed, or will throw no default constructor exception, keep in mind: to develop the habit of a certain class to write the default constructor for easy expansion.

Ambiguity automatic assembly

  If you are careful enough, you will find the test code bloggers meet the above automatic assembly, the injected Car does not use polymorphic written, the code is very low. In fact, I was to test by deliberately injecting a specific implementation, the actual business of course would not be so confined to write code. Because bloggers Car interface as well as a Mercedes implementation class BenzCar, if a multi-state writing, automatic assembly would be ambiguous issues, NoUniqueBeanDefinitionException will throw an exception. So, faced with this ambiguity, how to solve it? You must know that every bean Spring container management will have an ID as a unique identifier, in the above example, we describe QQCar class for Spring components when there is no clear set ID, but Spring will default component class of the class lowercase first letter of the name as the bean ID, but we also need a custom ID to identify our own business -

package spring.impl;

import org.springframework.stereotype.Component;
import spring.facade.Car;
//这里指定 chenbenbuyi 为组件的ID 
@Component("chenbenbuyi")
public class QQCar implements Car {
    @Override
    public void drive() {
        System.out.println("开QQ车");
    }
}

  But tests found that this did not solve the problem of ambiguity interface parameters in the automatic assembly, because the custom ID in the assembly is the latter issue is, when you make Spring select from multiple interfaces at the assembly stage to achieve automatic injection when the object instance, Spring can not choose - just like you told me that you just want to drive a car, each car also has a unique license plate number, but I still do not know what kind of car you want to open. How to do it? There are a variety of solutions, we can @Primary annotation we clearly need to automatically inject implementation class marked as the preferred bean, I thought so -

 package spring.impl;
 
 import org.springframework.context.annotation.Primary;
 import org.springframework.stereotype.Component;
 import spring.facade.Car;
 
 @Component
 @Primary
 public class BenzCar implements Car {
    @Override
    public void drive() {
        System.out.println("开奔驰车");
    }
}

  When the automatic assembly time, Spring face of ambiguity, priority will be marked as the preferred choice of the bean automatically injected. Of course, we can also use qualifier annotations when using @Autowired complete automatic assembly Only make a bean as an automatic injection bean--

 package spring.impl;
 
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Component;
 import spring.facade.Car;
 
 @Component
public class Man {
    private Car car;

    public Man() {
    }
    //普通方法实现自动装配
    @Autowired
    @Qualifier("chenbenbuyi") //限定ID为 chenbenbuyi 的bean被装配进来
    public void insertCar(Car car) {
       this.car = car;
    }

    public void work() {
        car.drive();
    }
}

  Since then, automatic assembly on Spring elaborated on almost, two other commonly used mechanism for assembling a series of articles will then explain in the next section of --Java Spring annotations and XML configuration. Bowen said are all original, as to reprint, please indicate the source; if set forth inappropriately place, welcome advice, be grateful.

Guess you like

Origin blog.csdn.net/qq_40914991/article/details/91400826