Spring IOC和DI
在Spring容器的底層,最重要的功能就是IOC和DI,也就是控制反轉和依賴注入。
IOC:控制反轉,将類的對象的建立交給Spring類管理建立。
DI:依賴注入,将類裡面的屬性在建立類的過程中給屬性指派。
DI和IOC的關系:DI不能單獨存在,DI需要在IOC的基礎上來完成。
在Spring内部,所有的元件都會放到IOC容器中,元件之間的關系通過IOC容器來自動裝配,也就是我們所說的依賴注入。接下來,我們就使用注解的方式來完成容器元件的注冊、管理及依賴、注入等功能。
在介紹使用注解完成容器元件的注冊、管理及依賴、注入等功能之前,我們先來看看使用XML檔案是如何注入Bean的。
通過XML檔案注入JavaBean
首先,我們在工程的io.mykit.spring.bean包下建立Person類,作為測試的JavaBean,代碼如下所示。
package io.mykit.spring.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.io.Serializable;
/**
* @author binghe
* @version 1.0.0
* @description 測試實體類
*/
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Person implements Serializable {
private static final long serialVersionUID = 7387479910468805194L;
private String name;
private Integer age;
}
接下來,我們在工程的resources目錄下建立Spring的配置檔案beans.xml,通過beans.xml檔案将Person類注入到Spring的IOC容器中,配置如下所示。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id = "person" class="io.mykit.spring.bean.Person">
<property name="name" value="binghe"></property>
<property name="age" value="18"></property>
</bean>
</beans>
到此,我們使用XML方式注入JavaBean就配置完成了。接下來,我們建立一個SpringBeanTest類來進行測試,這裡,我使用的是Junit進行測試,測試方法如下所示。
@Test
public void testXmlConfig(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = (Person) context.getBean("person");
System.out.println(person);
}
運作testXmlConfig()方法,輸出的結果資訊如下。
Person(name=binghe, age=18)
從輸出結果中,我們可以看出,Person類通過beans.xml檔案的配置,已經注入到Spring的IOC容器中了。
通過注解注入JavaBean
通過XML檔案,我們可以将JavaBean注入到Spring的IOC容器中。那使用注解又該如何實作呢?别急,其實使用注解比使用XML檔案要簡單的多,我們在項目的io.mykit.spring.plugins.register.config包下建立PersonConfig類,并在PersonConfig類上添加@Configuration注解來标注PersonConfig類是一個Spring的配置類,通過@Bean注解将Person類注入到Spring的IOC容器中。
package io.mykit.spring.plugins.register.config;
import io.mykit.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author binghe
* @version 1.0.0
* @description 以注解的形式來配置Person
*/
@Configuration
public class PersonConfig {
@Bean
public Person person(){
return new Person("binghe001", 18);
}
}
沒錯,通過PersonConfig類我們就能夠将Person類注入到Spring的IOC容器中,是不是很Nice!!主要我們在類上加上@Configuration注解,并在方法上加上@Bean注解,就能夠将方法中建立的JavaBean注入到Spring的IOC容器中。
接下來,我們在SpringBeanTest類中建立一個testAnnotationConfig()方法來測試通過注解注入的Person類,如下所示。
@Test
public void testAnnotationConfig(){
ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig.class);
Person person = context.getBean(Person.class);
System.out.println(person);
}
運作testAnnotationConfig()方法,輸出的結果資訊如下所示。
Person(name=binghe001, age=18)
可以看出,通過注解将Person類注入到了Spring的IOC容器中。
到這裡,我們已經明确,通過XML檔案和注解兩種方式都可以将JavaBean注入到Spring的IOC容器中。那麼,使用注解将JavaBean注入到IOC容器中時,使用的bean的名稱是什麼呢?我們可以在testAnnotationConfig()方法中添加如下代碼來擷取Person類型下的注解名稱。
//按照類型找到對應的bean名稱數組
String[] names = context.getBeanNamesForType(Person.class);
Arrays.stream(names).forEach(System.out::println);
完整的testAnnotationConfig()方法的代碼如下所示。
@Test
public void testAnnotationConfig(){
ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig.class);
Person person = context.getBean(Person.class);
System.out.println(person);
//按照類型找到對應的bean名稱數組
String[] names = context.getBeanNamesForType(Person.class);
Arrays.stream(names).forEach(System.out::println);
}
運作testAnnotationConfig()方法輸出的結果資訊如下所示。
Person(name=binghe001, age=18)
person
那這裡的person是啥?我們修改下PersonConfig類中的person()方法,将person()方法修改成person01()方法,如下所示。
package io.mykit.spring.plugins.register.config;
import io.mykit.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author binghe
* @version 1.0.0
* @description 以注解的形式來配置Person
*/
@Configuration
public class PersonConfig {
@Bean
public Person person01(){
return new Person("binghe001", 18);
}
}
此時,我們再次運作testAnnotationConfig()方法,輸出的結果資訊如下所示。
Person(name=binghe001, age=18)
person01
看到這裡,大家應該有種豁然開朗的感覺了,沒錯!!使用注解注入Javabean時,bean在IOC中的名稱就是使用@Bean注解标注的方法名稱。我們可不可以為bean單獨指定名稱呢?那必須可以啊!隻要在@Bean注解中明确指定名稱就可以了。比如下面的PersonConfig類的代碼,我們将person01()方法上的@Bean注解修改成@Bean("person")注解,如下所示。
package io.mykit.spring.plugins.register.config;
import io.mykit.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author binghe
* @version 1.0.0
* @description 以注解的形式來配置Person
*/
@Configuration
public class PersonConfig {
@Bean("person")
public Person person01(){
return new Person("binghe001", 18);
}
}
Person(name=binghe001, age=18)
person
可以看到,此時,輸出的JavaBean的名稱為person。
結論:我們在使用注解方式向Spring的IOC容器中注入JavaBean時,如果沒有在@Bean注解中明确指定bean的名稱,就使用目前方法的名稱來作為bean的名稱;如果在@Bean注解中明确指定了bean的名稱,則使用@Bean注解中指定的名稱來作為bean的名稱。