(三)测试学习JavaWeb之Spring IOC

前言

对于传统的应用程序,一般通过new object()来创建对象,主动权和创建时机由自己把控,而IOC意味着将创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象。对象的获取由主动变为被动,这就是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-依赖注入)你需要知道的一切

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容

  • 2.1 我们的理念是:让别人为你服务 IoC是随着近年来轻量级容器(Lightweight Container)的...
    好好学习Sun阅读 2,709评论 0 11
  • 什么是Spring Spring是一个开源的Java EE开发框架。Spring框架的核心功能可以应用在任何Jav...
    jemmm阅读 16,449评论 1 133
  • 来源:关于Spring IOC (DI-依赖注入)你需要知道的一切作者:zejian Dao层(AccountDa...
    杨井阅读 5,331评论 0 27
  • 本来是准备看一看Spring源码的。然后在知乎上看到来一个帖子,说有一群**自己连Spring官方文档都没有完全读...
    此鱼不得水阅读 6,930评论 4 21
  • 之前的学习,没有追问自己。 一方面是自己本来就不是很懂,怕追问太多自己更加混乱 另一方面是自己追问太多,自己的成绩...
    大海dahai阅读 135评论 0 0