(三)測試學習JavaWeb之Spring IOC

前言

對於傳統的應用程序,一般通過new object()來創建對象,主動權和創建時機由自己把控,而IOC意味着將創建和查找依賴對象的控制權交給了容器,由容器進行注入組合對象。對象的獲取由主動變爲被動,這就是IOC控制反轉的設計思想。


快速入門

pom依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>Spring</groupId>
    <artifactId>SpringLearn</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
            <spring.version>4.1.4.RELEASE</spring.version>
    </properties>

    <dependencies>

        <!-- Spring Core -->
        <!-- http://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- Spring Context -->
        <!-- http://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

    </dependencies>
</project>
代碼示例

創建HelloWorld接口

package com.demo;

public interface HelloWorld {
    void sayHello();
}

創建接口實現類

package com.demo;

public class SpringHelloWorld implements HelloWorld {

    public void sayHello() {
        System.out.println("Spring say Hello!");
    }
}

創建service層

package com.demo;

public class HelloWorldService {

    //@Autowired
    //@Qualifier("strutsHelloWorld")
    private HelloWorld hello;
    private String name;

    public void setHelloWorld(HelloWorld hello) {
        this.hello = hello;
    }

    public void setName(String name){
        this.name = name;
    }

    public HelloWorld getHelloWorld() {
        System.out.println(this.name);
        return hello;
    }
}

配置bean文件,property的name屬性的值需要與HelloWorldService類的set方法名後半部分名稱一致,比如setHelloWorld方法,則name值爲helloWorld。ref指向創建的對象springHelloWorld,作用是把對象傳遞給HelloWorldService的HelloWorld屬性,該屬性必須擁有set方法(上述代碼的setHelloWorld方法)才能注入成功。

<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-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <!--context:annotation-config /-->

    <!-- 聲明springHelloWorld對象,由spring創建 -->
    <bean id="springHelloWorld"
          class="com.demo.SpringHelloWorld"></bean>
    
    <!-- 聲明helloWorldService對象,由spring創建 -->
    <bean id="helloWorldService"
          class="com.demo.HelloWorldService">
        <!--注入springHelloWorld對象,需要setHelloWorld方法-->
        <property name="helloWorld" ref="springHelloWorld"/>
        <!--注入name變量值,需要setName方法-->
        <property name="name" value="Tomandy"/>
    </bean>

</beans>

創建測試類

package com.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestHelloWorld {

    public static void main(String[] args) {
        //加載配置文件,默認查找classpath路徑下的文件
        ApplicationContext context =
                new ClassPathXmlApplicationContext("helloWorldBeans.xml");

        //spring默認創建是單實例的作用域
        HelloWorldService helloWorldService =
                (HelloWorldService) context.getBean("helloWorldService");

        HelloWorld helloWorld = helloWorldService.getHelloWorld();
        helloWorld.sayHello();
    }
}

運行測試類,輸出結果爲

"C:\Program Files (x86)\Java\jdk1.8.0_111\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.2\lib\idea_rt.jar=36108:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-32.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\rt.jar;D:\github\SpringLearn\target\test-classes;D:\github\SpringLearn\target\classes;C:\Users\lenovo\.m2\repository\org\springframework\spring-core\4.1.4.RELEASE\spring-core-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-context\4.1.4.RELEASE\spring-context-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-aop\4.1.4.RELEASE\spring-aop-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-beans\4.1.4.RELEASE\spring-beans-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-expression\4.1.4.RELEASE\spring-expression-4.1.4.RELEASE.jar" com.demo.TestHelloWorld
三月 01, 2019 2:13:54 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@197848c: startup date [Fri Mar 01 14:13:54 CST 2019]; root of context hierarchy
三月 01, 2019 2:13:54 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [helloWorldBeans.xml]
Tomandy
Spring say Hello!

Process finished with exit code 0

通過以上示例,可輕鬆瞭解IOC的使用了,即通過xml配置文件,spring可以幫助我們創建對象springHelloWorld,並注入helloWorldService中,上述代碼使用的setter注入方式,還可以通過構造函數、註解、靜態工廠、實例工廠來注入,下面文章再說明。
除了通過ClassPathXmlApplicationContext去加載spring的配置文件,還可以通過FileSystemXmlApplicationContext去加載,區別在於前者默認查找classpath路徑下的文件,後者默認查找項目工作路徑,即項目的根目錄,文章《關於Spring IOC (DI-依賴注入)你需要知道的一切》舉例如下。

//默認查找classpath路徑下的文件 
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring/spring-ioc.xml"); 
//多文件,也可傳遞數組 
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring/spring-ioc.xml","spring/spring-ioc2.xml",.....); 
//默認爲項目工作路徑 即項目的根目錄 
FileSystemXmlApplicationContext applicationContext= new FileSystemXmlApplicationContext("/src/main/resources/spring/spring-ioc.xml"); 
//也可以讀取classpath下的文件 
FileSystemXmlApplicationContext applicationContext=new FileSystemXmlApplicationContext("classpath:spring/spring-ioc.xml"); 
//使用前綴file 表示的是文件的絕對路徑 
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("file:D:/app.spring.xml"); 
//多文件與ClassPathXmlApplicationContext相同

基於xml的自動裝配

上述例子bean文件配置了property屬性,實際屬於手工裝配,spring也提供了自動裝配的方式,分別有byName,byType,constructor三種方式,下面通過舉例來說明他們之間的區別。

  • byName,顧名思義就是按照名稱匹配。根據bean名稱去和set方法的後半部分名稱匹配,如果一致,則注入成功,否則失敗。
    配置bean文件
<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-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <context:annotation-config/>

    <bean id="helloWorld"
          class="com.demo.SpringHelloWorld"></bean>

    <bean id="helloWorldService"
          autowire="byName"
          class="com.demo.HelloWorldService">
    </bean>

</beans>

創建HelloWorldService

package com.demo;

public class HelloWorldService {

    private HelloWorld helloWorld;

    public void setHelloWorld(HelloWorld helloWorld) {
        this.helloWorld = helloWorld;
    }

    public HelloWorld getHelloWorld() {
        return helloWorld;
    }
}

byName模式會根據beanid helloWorld去和setHelloWorld方法的後半部分名稱(HelloWorld)比對,如果(首字母轉換爲大寫)一致則注入成功。

  • byType,即按照類型匹配。Spring容器會基於反射查看bean定義的類,然後找到與set方法參數類型相同的bean來注入,需要通過set方法來實現。
    配置bean文件,注意用到了autowire屬性。
<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-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <context:annotation-config/>

    <bean id="springHelloWorld"
          class="com.demo.SpringHelloWorld"></bean>

    <bean id="helloWorldService"
          autowire="byType"
          class="com.demo.HelloWorldService">
    </bean>

</beans>

創建HelloWorldService

package com.demo;

public class HelloWorldService {

    private HelloWorld helloWorld;

    public void setHelloWorld(HelloWorld helloWorld) {
        this.helloWorld = helloWorld;
    }

    public HelloWorld getHelloWorld() {
        return helloWorld;
    }
}

運行測試類,輸出結果爲

Spring say Hello!

當存在多個相同類型的bean時,使用byType方式會報錯,此時可以通過autowire-candidate="false"來跳過相同類型的bean。

<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-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <context:annotation-config/>

    <bean id="springHelloWorld"
          class="com.demo.SpringHelloWorld"></bean>

    <bean id="springHelloWorld1"
          autowire-candidate="false"
          class="com.demo.SpringHelloWorld"></bean>

    <bean id="helloWorldService"
          autowire="byType"
          class="com.demo.HelloWorldService">
    </bean>

</beans>
  • constructor,在該模式下Spring容器同樣會嘗試找到那些類型與構造函數相同匹配的bean注入。當存在多個類型相同bean時,按名稱優先匹配,如果沒有找到對應名稱,則注入失敗,此時可以使用autowire-candidate=”false” 過濾來解決。
<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-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <context:annotation-config/>

    <!--如果存在多個相同類型的,則按byName來匹配-->
    <bean id="helloWorld"
          class="com.demo.SpringHelloWorld"></bean>

    <bean id="helloWorld2"
          autowire-candidate="false"
          class="com.demo.SpringHelloWorld"></bean>

    <bean id="helloWorldService"
          autowire="constructor"
          class="com.demo.HelloWorldService">
    </bean>

</beans>
package com.demo;

public class HelloWorldService {

    private HelloWorld helloWorld;

    public HelloWorldService(HelloWorld helloWorld){
        this.helloWorld = helloWorld;
    }

    public HelloWorld getHelloWorld() {
        return helloWorld;
    }
}

依賴注入

除了上文提到的setter注入,還可以通過構造函數、註解、靜態工廠、實例工廠注入。

構造函數注入

spring容器會根據bean中指定的構造函數參數來決定調用那個構造函數。
創建HelloWorldService

package com.demo;

import java.util.List;
import java.util.Map;

public class HelloWorldService {

    //@Autowired
    //@Qualifier("strutsHelloWorld")
    private HelloWorld hello;
    private String name;
    private List<String> list;
    private Map<String, String> map;


    public HelloWorldService(HelloWorld hello, String name, List<String> list, Map<String, String> map) {
        this.hello = hello;
        this.name = name;
        this.list = list;
        this.map = map;
    }

    public HelloWorld getHelloWorld() {
        System.out.println(this.name);
        for (int i = 0; i < list.size(); i++) {
            System.out.println("第" + i + "個列表值:" + list.get(i));
        }

        for (String key : map.keySet()) {
            System.out.println("key爲:" + key + " value爲:" + map.get(key));
        }
        return hello;
    }
}

配置xml文件

<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-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <!--context:annotation-config /-->

    <bean id="springHelloWorld"
          class="com.demo.SpringHelloWorld"></bean>

    <bean id="helloWorldService"
          class="com.demo.HelloWorldService">
        <!--注入,需要set方法-->
        <!--
        <property name="helloWorld" ref="springHelloWorld"/>
        <property name="name" value="Tomandy"/>
        -->
        <constructor-arg ref="springHelloWorld"/>
        <constructor-arg type="java.lang.String" value="Tomandy"/>
        <constructor-arg>
            <list>
                <value>tom1</value>
                <value>tom2</value>
            </list>
        </constructor-arg>
        <constructor-arg>
            <map>
                <entry key="key1" value="value1">
                </entry>

                <entry key="key2" value="value2">
                </entry>
            </map>
        </constructor-arg>

    </bean>

</beans>

運行測試後,輸出結果如下。

"C:\Program Files (x86)\Java\jdk1.8.0_111\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.2\lib\idea_rt.jar=42191:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-32.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\rt.jar;D:\github\SpringLearn\target\test-classes;D:\github\SpringLearn\target\classes;C:\Users\lenovo\.m2\repository\org\springframework\spring-core\4.1.4.RELEASE\spring-core-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-context\4.1.4.RELEASE\spring-context-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-aop\4.1.4.RELEASE\spring-aop-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-beans\4.1.4.RELEASE\spring-beans-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-expression\4.1.4.RELEASE\spring-expression-4.1.4.RELEASE.jar" com.demo.TestHelloWorld
三月 01, 2019 4:17:54 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@197848c: startup date [Fri Mar 01 16:17:54 CST 2019]; root of context hierarchy
三月 01, 2019 4:17:54 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [helloWorldBeans.xml]
Tomandy
第0個列表值:tom1
第1個列表值:tom2
key爲:key1 value爲:value1
key爲:key2 value爲:value2
Spring say Hello!

Process finished with exit code 0

註解注入

需在bean文件加上以下內容,註解注入才生效。

<context:annotation-config />
  • 可以通過@Autowired對成員變量、set方法、構造函數進行標註來實現依賴注入,該註解默認按byType匹配,如果需要按byName匹配,可以通過@Qualifier來指定對象的名稱,指定的名稱需與bean文件的對象名稱一致,否則會報錯。
    創建HelloWorldService
package com.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class HelloWorldService {

    @Autowired
    @Qualifier("springHelloWorld")
    private HelloWorld helloWorld;

    public HelloWorld getHelloWorld() {
        return helloWorld;
    }
}

配置bean文件

<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-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <context:annotation-config />

    <bean id="springHelloWorld"
          class="com.demo.SpringHelloWorld"></bean>

    <bean id="helloWorldService"
          class="com.demo.HelloWorldService">
    </bean>

</beans>

運行測試類,輸出結果如下。

"C:\Program Files (x86)\Java\jdk1.8.0_111\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.2\lib\idea_rt.jar=47086:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-32.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\rt.jar;D:\github\SpringLearn\target\test-classes;D:\github\SpringLearn\target\classes;C:\Users\lenovo\.m2\repository\org\springframework\spring-core\4.1.4.RELEASE\spring-core-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-context\4.1.4.RELEASE\spring-context-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-aop\4.1.4.RELEASE\spring-aop-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-beans\4.1.4.RELEASE\spring-beans-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-expression\4.1.4.RELEASE\spring-expression-4.1.4.RELEASE.jar" com.demo.TestHelloWorld
三月 01, 2019 5:48:05 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@197848c: startup date [Fri Mar 01 17:48:05 CST 2019]; root of context hierarchy
三月 01, 2019 5:48:06 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [helloWorldBeans.xml]
Spring say Hello!

Process finished with exit code 0

通過以上例子可發現,通過標註成員變量,可以省略set方法和構造函數,大大簡化了代碼。

  • @Resource的功能與@Autowired類似,但不能標註構造函數。默認按照byName進行裝配,名稱可以通過name屬性進行指定,如果沒有指定name屬性,當註解寫在成員變量上時,默認取成員變量名進行byName查找,如果註解寫在setter方法上默認取屬性名進行裝配。 當找不到與名稱匹配的bean時才按照byType進行裝配。
package com.demo;

import javax.annotation.Resource;

public class HelloWorldService {

    // 先按helloWorld去查找bean對象,找不到再byType
    @Resource
    private HelloWorld helloWorld;

    public HelloWorld getHelloWorld() {
        return helloWorld;
    }
}

package com.demo;

import javax.annotation.Resource;

public class HelloWorldService {

    //通過byName查找
    @Resource(name = "springHelloWorld")
    private HelloWorld helloWorld;

    public HelloWorld getHelloWorld() {
        return helloWorld;
    }
}

package com.demo;

import javax.annotation.Resource;

public class HelloWorldService {

    //通過byType查找
    @Resource(type = HelloWorld.class)
    private HelloWorld helloWorld;

    public HelloWorld getHelloWorld() {
        return helloWorld;
    }
}

  • @Autowired和@Resource不適合簡單類型的裝配,如int,String等。可以通過@Value來注入,該註解一般與properties文件結合使用,其提了兩種使用方式,SPEL表達式和佔位符,舉例如下。
    新建config.properties文件
url=http://10.1.1.1
port=8080
username=Tomandy
password=Tom123

配置bean文件

<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-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <context:annotation-config/>

    <!--基於佔位符方式-->
    <bean id="config" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
        <property name="location" value="config.properties"/>
    </bean>

    <!--基於SPEL表達式-->
    <bean id="configSpel" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="locations">
            <list>
                <value>config.properties</value>
            </list>
        </property>
    </bean>

    <bean id="springHelloWorld"
          class="com.demo.SpringHelloWorld"></bean>

    <bean id="helloWorldService"
          class="com.demo.HelloWorldService">
    </bean>

</beans>

創建HelloWorldService

package com.demo;

import org.springframework.beans.factory.annotation.Value;

import javax.annotation.Resource;

public class HelloWorldService {

    @Resource(type = HelloWorld.class)
    private HelloWorld helloWorld;

    @Value("${url}")
    private String url;

    @Value("#{configSpel['username']}")
    private String userName;

    public HelloWorld getHelloWorld() {
        System.out.println(this.url);
        System.out.println(this.userName);
        return helloWorld;
    }
}

運行測試類,輸出結果如下

"C:\Program Files (x86)\Java\jdk1.8.0_111\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.2\lib\idea_rt.jar=48850:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-32.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\rt.jar;D:\github\SpringLearn\target\test-classes;D:\github\SpringLearn\target\classes;C:\Users\lenovo\.m2\repository\org\springframework\spring-core\4.1.4.RELEASE\spring-core-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-context\4.1.4.RELEASE\spring-context-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-aop\4.1.4.RELEASE\spring-aop-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-beans\4.1.4.RELEASE\spring-beans-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-expression\4.1.4.RELEASE\spring-expression-4.1.4.RELEASE.jar" com.demo.TestHelloWorld
三月 01, 2019 6:23:41 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@197848c: startup date [Fri Mar 01 18:23:41 CST 2019]; root of context hierarchy
三月 01, 2019 6:23:41 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [helloWorldBeans.xml]
三月 01, 2019 6:23:41 下午 org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer loadProperties
信息: Loading properties file from class path resource [config.properties]
三月 01, 2019 6:23:41 下午 org.springframework.beans.factory.config.PropertiesFactoryBean loadProperties
信息: Loading properties file from class path resource [config.properties]
http://10.1.1.1
Tomandy
Spring say Hello!

Process finished with exit code 0

靜態工廠、實例工廠注入

基於工廠注入的方式參考以下文章《spring的五種依賴注入方式》

@Service及@Repository註解

在bean配置文件加上包掃描路徑,將自動掃描路徑包,如果類帶了@Service註解,將自動註冊到Spring容器,不需要在bean配置文件定義bean了,類似的註解還有@Component、@Repository、@Controller,舉例如下。
配置bean文件,通過使用@Service註解,替換了原先的HelloWorldService的bean配置。

<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-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <!-- 聲明包掃描 -->
    <context:component-scan base-package="com.demo" />

    <bean id="springHelloWorld"
          class="com.demo.SpringHelloWorld"></bean>

</beans>

創建HelloWorldService

package com.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("helloWorldService")
public class HelloWorldService {

    @Autowired
    private HelloWorld helloWorld;

    public HelloWorld getHelloWorld() {
        return helloWorld;
    }
}

創建測試類

package com.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestHelloWorld {


    public static void main(String[] args) {
        //加載配置文件
        ApplicationContext context =
                new ClassPathXmlApplicationContext("helloWorldBeans.xml");

        //spring默認創建是單實例的作用域
        HelloWorldService helloWorldService =
                (HelloWorldService) context.getBean("helloWorldService");

        HelloWorld helloWorld = helloWorldService.getHelloWorld();
        helloWorld.sayHello();
    }
}

運行測試類,輸出結果爲

"C:\Program Files (x86)\Java\jdk1.8.0_111\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.2\lib\idea_rt.jar=52126:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-32.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files (x86)\Java\jdk1.8.0_111\jre\lib\rt.jar;D:\github\SpringLearn\target\test-classes;D:\github\SpringLearn\target\classes;C:\Users\lenovo\.m2\repository\org\springframework\spring-core\4.1.4.RELEASE\spring-core-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-context\4.1.4.RELEASE\spring-context-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-aop\4.1.4.RELEASE\spring-aop-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-beans\4.1.4.RELEASE\spring-beans-4.1.4.RELEASE.jar;C:\Users\lenovo\.m2\repository\org\springframework\spring-expression\4.1.4.RELEASE\spring-expression-4.1.4.RELEASE.jar" com.demo.TestHelloWorld
三月 01, 2019 7:30:09 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@197848c: startup date [Fri Mar 01 19:30:09 CST 2019]; root of context hierarchy
三月 01, 2019 7:30:09 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [helloWorldBeans.xml]
Spring say Hello!

Process finished with exit code 0

參考資料

談談對Spring IOC的理解
關於Spring IOC (DI-依賴注入)你需要知道的一切

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章