Spring依赖注入

1. 前言

本篇博客主要通过代码练习Spring框架的依赖注入。

  • 基于XML配置文件的依赖注入
  • 基于注解的依赖注入

依赖,指的是类A的功能实现,需要类B的相关属性和方法。那么类A对类B就有依赖。

通过Spring的控制反转【IOC】功能,就能够把所有的bean(java类)注册到Spring的容器,通过容器的管理功能,来实现类B注入到类A中,通过解耦的方式实现类A的依赖注入。

Spring可以解析XML配置文件来得知如何注册bean A和bean B,也能够知道如何把bean B注入到bean A,比如通过set设值注入 ,或者构造方法注入等。而注入的过程已经不是开发者需要关注的了,对开发者透明的,开发者这需要指定如何注入就可以了,注入的过程由Spring bean容器进行完成和管理。

为了应对大型软件架构的复杂性,尤其是配置的复杂性,通过注解实现依赖注入的方式成为必然。当然也可以XML和注解同时存在。

本篇博客参考以下博客内容:

  1. https://bbs.huaweicloud.com/blogs/327394
  2. https://bbs.huaweicloud.com/blogs/327710
  3. https://bbs.huaweicloud.com/blogs/329482

2 开发环境

本篇在虚拟机node99里面安装了JDK开发环境。

[root@node99][/opt]
# cat /etc/redhat-release 
CentOS Linux release 8.5.2111
[root@node99][/opt]
# java -version
java version "17" 2021-09-14 LTS
Java(TM) SE Runtime Environment (build 17+35-LTS-2724)
Java HotSpot(TM) 64-Bit Server VM (build 17+35-LTS-2724, mixed mode, sharing)
[root@node99][/opt]
# mvn --version
Apache Maven 3.8.2 (ea98e05a04480131370aa0c110b8c54cf726c06f)
Maven home: /opt/apache/maven/3.8.2
Java version: 17, vendor: Oracle Corporation, runtime: /opt/jdk/jdk-17
Default locale: zh_CN, platform encoding: UTF-8
OS name: "linux", version: "4.18.0-348.el8.x86_64", arch: "amd64", family: "unix"
[root@node99][/opt]
# catalina.sh --version
Using CATALINA_BASE:   /opt/apache/tomcat/8.5.70
Using CATALINA_HOME:   /opt/apache/tomcat/8.5.70
Using CATALINA_TMPDIR: /opt/apache/tomcat/8.5.70/temp
Using JRE_HOME:        /opt/jdk/jdk-17
Using CLASSPATH:       /opt/apache/tomcat/8.5.70/bin/bootstrap.jar:/opt/apache/tomcat/8.5.70/bin/tomcat-juli.jar
Using CATALINA_OPTS:   
Usage: catalina.sh ( commands ... )
commands:
  debug             Start Catalina in a debugger
  debug -security   Debug Catalina with a security manager
  jpda start        Start Catalina under JPDA debugger
  run               Start Catalina in the current window
  run -security     Start in the current window with security manager
  start             Start Catalina in a separate window
  start -security   Start in a separate window with security manager
  stop              Stop Catalina, waiting up to 5 seconds for the process to end
  stop n            Stop Catalina, waiting up to n seconds for the process to end
  stop -force       Stop Catalina, wait up to 5 seconds and then use kill -KILL if still running
  stop n -force     Stop Catalina, wait up to n seconds and then use kill -KILL if still running
  configtest        Run a basic syntax check on server.xml - check exit code for result
  version           What version of tomcat are you running?
Note: Waiting for the process to end and use of the -force option require that $CATALINA_PID is defined

创建项目放置目录:

mkdir /root/liwl_dev/java/web/spring

使用mvn创建项目:

mvn archetype:generate -DgroupId=com.liwl.dev -DartifactId=SpringDI -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

使用vscode连接node99,然后打开项目文件。

在项目管理配置文件pom.xml里面,添加以下内容

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.liwl.dev</groupId>
  <artifactId>SrpingDI</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>LiwlSrping5Dev</name>
  <url>http://maven.apache.org</url>
    
  <properties>
        <spring.version>5.3.15</spring.version>
  </properties>

  <dependencies>
      
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
    </dependency>
  
     <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
     </dependency>
      
  </dependencies>
    
  <build>
  	<plugins>
    	<plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            	<configuration>
            	    <source>17</source>
                    <target>17</target>
                    <encoding>UTF8</encoding>
                </configuration>
         </plugin>
    </plugins>
  </build>

/root/liwl_dev/java/web/spring/SpringDI/src/main目录下,创建resources目录。在该目录下创建用来配置bean的XML文件springdi.xml

<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-3.0.xsd">

</beans>

3. 使用XML配置文件进行依赖注入

3.1 set设值注入

3.1.1 基本数据类型注入

在目录/root/liwl_dev/java/web/spring/SpringDI/src/main/java/com/liwl/dev下创建源码文件LiwanLiang.java

package com.liwl.dev;

public interface LiwanLiang {
    
}

同一目录下创建接口LiwanLiang的实现类LiwanLiangImpl.java

package com.liwl.dev;

public class LiwanLiangImpl implements LiwanLiang {
    
    private String name;
    private int age;

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

    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "学生信息:"+"name:"+name+","+"age:"+age;
    }
}

修改/root/liwl_dev/java/web/spring/SpringDI/src/main/resources目录下的srpingdi.xml内容

<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-3.0.xsd">

    <bean id="liwl" class="com.liwl.dev.LiwanLiangImpl">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
    </bean>

</beans>

在目录/root/liwl_dev/java/web/spring/SpringDI/src/test/java/com/liwl/dev下创建测试代码LiwlTest.java

package com.liwl.dev;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class LiwlTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springdi.xml");
        LiwanLiangImpl liwl = (LiwanLiangImpl) context.getBean("liwl");
        System.out.println(liwl);
        context.close();
    }
}

执行测试代码,结果

liwanliang信息:name:liwanliang,age:30

3.1.2 引用数据类型注入

以LiwanLiangImpl依赖SchoolImpl为例子。

首先创建接口源文件School.java和实现类源文件SchoolImpl.java

package com.liwl.dev;

public interface School {
    
}
package com.liwl.dev;

public class SchoolImpl implements School {

    private String name;
    private String address;

    public String getName() {
        return name;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
    
    @Override
    public String toString() {
        return "学校信息:"+"名称:"+name+","+"地址:"+address;
    }
}

修改LiwanLiangImpl.java,加入school属性

package com.liwl.dev;

public class LiwanLiangImpl implements LiwanLiang {
    
    private String name;
    private int age;
    private School school;

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

    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }

    public School getSchool() {
        return school;
    }

    public void setSchool(School school) {
        this.school = school;
    }
}

修改srpingdi.xml文件

<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-3.0.xsd">

    <bean id="liwl" class="com.liwl.dev.LiwanLiangImpl">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
        <property name="school" ref="school"/>
    </bean>

    <bean id="school" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="江南大学"/>
        <property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号"/>
    </bean>

</beans>

修改LiwanLiangImpl.java里面toString方法内容

@Override
public String toString() {
	return "学生信息:"+"name:"+name+","+"age:"+age+"学校信息:"+school;
}

运行测试源码文件LiwlTest.java

学生信息:name:liwanliang,age:30学校信息:学校信息:名称:江南大学,地址:江苏省无锡市滨湖区蠡湖大道1800号

3.1.3 其他引用类型注入

a. List集合注入基本类型

修改LiwanLiangImpl.java,增加属性stringList

package com.liwl.dev;

import java.util.List;

public class LiwanLiangImpl implements LiwanLiang {
    
    private String name;
    private int age;
    private School school;
    private List<String> course;

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

    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }

    public School getSchool() {
        return school;
    }

    public void setSchool(School school) {
        this.school = school;
    }

    public void setCourse(List<String> course) {
        this.course = course;
    }

    public List<String> getCourse() {
        return course;
    }

    @Override
    public String toString() {
        return "学生信息:"+"name:"+name+","+"age:"+age+","+".学校信息:"+school+".其他:"+course;
    }
}

修改springdi.xml

<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-3.0.xsd">

    <bean id="liwl" class="com.liwl.dev.LiwanLiangImpl">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
        <property name="school" ref="school"/>
        <property name="course">
            <list>
                <value>"高等数学"</value>
                <value>"线性代数"</value>
                <value>"工程制图"</value>
            </list>
        </property>
    </bean>

    <bean id="school" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="江南大学"/>
        <property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号"/>
    </bean>

</beans>

运行结果

学生信息:name:liwanliang,age:30,.学校信息:学校信息:名称:江南大学,地址:江苏省无锡市滨湖区蠡湖大道1800号.其他:["高等数学", "线性代数", "工程制图"]

b. List集合注入引用类型

这里把school对象增加一个

修改LiwanLiangImpl.java

package com.liwl.dev;

import java.util.List;

public class LiwanLiangImpl implements LiwanLiang {
    
    private String name;
    private int age;
    private List<School> schoolList;
    private List<String> course;

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

    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }

    public List<School> getSchoolList() {
        return schoolList;
    }

    public void setSchoolList(List<School> schoolList) {
        this.schoolList = schoolList;
    }

    public void setCourse(List<String> course) {
        this.course = course;
    }

    public List<String> getCourse() {
        return course;
    }

    @Override
    public String toString() {
        return "学生信息:"+"name:"+name+","+"age:"+age+","+".学校信息:"+schoolList+".其他:"+course;
    }
}

修改springdi.xml

<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-3.0.xsd">

    <bean id="liwl" class="com.liwl.dev.LiwanLiangImpl">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
        <!-- 
        <property name="school" ref="school"/>
        -->
        <property name="schoolList">
            <list>
                <ref bean="school01"></ref>
                <ref bean="school02"></ref>
            </list>
        </property>
        <property name="course">
            <list>
                <value>"高等数学"</value>
                <value>"线性代数"</value>
                <value>"工程制图"</value>
            </list>
        </property>
    </bean>

    <bean id="school01" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="江南大学01"/>
        <property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号"/>
    </bean>

    <bean id="school02" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="江南大学02"/>
        <property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号"/>
    </bean>

</beans>

运行结果

学生信息:name:liwanliang,age:30,.学校信息:[学校信息:名称:江南大学01,地址:江苏省无锡市滨湖区蠡湖大道1800号, 学校信息:名称:江南大学02,地址:江苏省无锡市滨湖区蠡湖大道1800号].其他:["高等数学", "线性代数", "工程制图"]

c. Map集合注入

修改LiwanLiangImpl.java

package com.liwl.dev;

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

public class LiwanLiangImpl implements LiwanLiang {
    
    private String name;
    private int age;
    private Map<String,School> schoolMap;
    private List<String> course;

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

    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }

    public Map<String, School> getSchoolMap() {
        return schoolMap;
    }

    public void setSchoolMap(Map<String, School> schoolMap) {
        this.schoolMap = schoolMap;
    }

    public void setCourse(List<String> course) {
        this.course = course;
    }

    public List<String> getCourse() {
        return course;
    }

    @Override
    public String toString() {
        return "学生信息:"+"name:"+name+","+"age:"+age+","+".学校信息:"+schoolMap+".其他:"+course;
    }
}

修改springdi.xml

<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-3.0.xsd">

    <bean id="liwl" class="com.liwl.dev.LiwanLiangImpl">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
        <property name="schoolMap">
            <map>
                <entry key="school01" value-ref="school01"></entry>
                <entry key="school02" value-ref="school02"></entry>
            </map>
        </property>

        <property name="course">
            <list>
                <value>"高等数学"</value>
                <value>"线性代数"</value>
                <value>"工程制图"</value>
            </list>
        </property>
    </bean>

    <bean id="school01" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="江南大学01"/>
        <property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号"/>
    </bean>

    <bean id="school02" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="江南大学02"/>
        <property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号"/>
    </bean>

</beans>

d. Properties类型注入

待补充

3.1.4 其他配置文件引入

在实际开发过程中,当把所有配置都放在同一个配置文件中时,会导致Spring的配置繁多,复杂,体积庞大。所以根据项目规划,在Spring主要配置文件中,通过import标签引入其他配置文件。这样可以是配置文件得到简化,易于配置修改和维护。

在目录/root/liwl_dev/java/web/spring/SpringDI/src/main/resources下创建liwanliang.xml和school.xml

修改springdi.xml

<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-3.0.xsd">

    <import resource="liwanliang.xml" />
    <import resource="school.xml" />

</beans>

修改liwanliang.xml

<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-3.0.xsd">

    <bean id="liwl" class="com.liwl.dev.LiwanLiangImpl">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
        <property name="school" ref="school"/>
    </bean>

</beans>

修改school.xml

<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-3.0.xsd">

    <bean id="school" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="江南大学01"/>
        <property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号"/>
    </bean>

</beans>

修改LiwanLiangImpl.java

package com.liwl.dev;

import java.util.List;

public class LiwanLiangImpl implements LiwanLiang {
    
    private String name;
    private int age;
    private School school;
    private List<String> course;

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

    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }

    public School getSchool() {
        return school;
    }

    public void setSchool(School school) {
        this.school = school;
    }

    public void setCourse(List<String> course) {
        this.course = course;
    }

    public List<String> getCourse() {
        return course;
    }

    @Override
    public String toString() {
        return 
            "name:"+name
            +","+
            "age:"+age
            + ","+
            "school"+school
            ;
    }
}

运行结果

name:liwanliang,age:30,schoolname:江南大学01,address:江苏省无锡市滨湖区蠡湖大道1800号

3.2 构造方法注入

spring按照无参构造函数来创建对象。如果一个类创建了有参构造函数,需要在XML里面配置构造函数。

修改liwanliang.xml

<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-3.0.xsd">

    <bean id="liwl" class="com.liwl.dev.LiwanLiangImpl">
        <constructor-arg name="name" value="liwanliang"/>
        <constructor-arg name="age" value="30"/>
        <constructor-arg name="school" ref="school"/>
    </bean>

</beans>

修改LiwanLiangImpl.java

package com.liwl.dev;

public class LiwanLiangImpl implements LiwanLiang {
    
    private String name;
    private int age;
    private School school;

    public LiwanLiangImpl(String name,int age,School school){
        this.name = name;
        this.age = age;
        this.school = school;
    }

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

    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }

    public School getSchool() {
        return school;
    }

    public void setSchool(School school) {
        this.school = school;
    }

    @Override
    public String toString() {
        return 
            "name:"+name
            +","+
            "age:"+age
            + ","+
            "school"+school
            ;
    }
}

运行结果

name:liwanliang,age:30,schoolname:江南大学01,address:江苏省无锡市滨湖区蠡湖大道1800号

3.3 自动注入

手动配置要注入的bean,数量变多时,会经常出错。Spring提供了自动注入的方式。

配置以后,不需要为要配置的bean指定其他需要注入的bean,Spring会在指定路径下扫描全部的bean,发现了需要自动注入的bean以后,会为要配置的bean自动注入。

3.3.1 按照名称注入

修改liwanliang.xml

<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-3.0.xsd">

    <bean id="liwl" class="com.liwl.dev.LiwanLiangImpl" autowire="byName">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
    </bean>

</beans>

当使用autowire=byName后,Spring会扫描容器里面全部注册的bean,然后发现LiwanLiangImpl需要School的bean,且School的bean具有get/set属性,因此就把School的bean自动注入到LiwanLiangImpl里面,不需要在XML里面手动为LiwanLiangImpl来指定bean

修改liwanliang.xml的配置,运行程序得到结果

name:liwanliang,age:30,schoolname:江南大学01,address:江苏省无锡市滨湖区蠡湖大道1800号

修改LiwanLiangImpl.java

package com.liwl.dev;

public class LiwanLiangImpl implements LiwanLiang {
    
    private String name;
    private int age;
    private School school;

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

    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }

    public School getSchool() {
        return school;
    }

    public void setSchool(School school) {
        this.school = school;
    }

    @Override
    public String toString() {
        return 
            "name:"+name
            +","+
            "age:"+age
            + ","+
            "school"+school
            ;
    }
}

3.3.2 按照类型注入

待补充

4. 半注解方式注入

半注解的方式,是在XML配置文件中,通过标签来设置Spring要扫描和注册的bean。然后在源码中通过注解就可以免除配置XML了。

4.1 注解类型

  • 第一组注解:关于对象实例化创建
    • @Component 使用在类上用于实例化Bean
    • @Controller 使用在web层类上用于实例化Bean
    • @Service 使用在service层类上用于实例化Bean
    • @Repository 使用在dao层类上用于实例化Bean
  • 第二组注解:对象属性的注入
    • @Autowired 用在引用数据类型属性的注入
    • @Resource
    • @Qulifier 与@Autowired一起使用
  • 第三组注解:字符串注入
    • @Value 基本数据类型的注入
    • @ProertySource 引入外部properties文件
    • @Bean 将方法的返回注入spring容器

4.2 使用实例

本部分通过XML来注册扫描器,通过注解注册LiwanLiangImpl的bean和School的bean。

修改springdi.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.xsd 
        http://www.springframework.org/schema/context 
        https://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 
        注册扫描器
    -->
    <context:component-scan base-package="com.liwl.dev"/>

</beans>

修改LiwanLiangImpl.java

package com.liwl.dev;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component(value = "liwl")
public class LiwanLiangImpl implements LiwanLiang {
    
    @Value(value = "liwanliang")
    private String name;
    @Value(value = "30")
    private int age;
    @Autowired
    private School school;

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

    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }

    public School getSchool() {
        return school;
    }

    public void setSchool(School school) {
        this.school = school;
    }


    @Override
    public String toString() {
        return 
            "name:"+name
            +","+
            "age:"+age
            +","+
            "school"+school
            ;
    }
}

修改SchoolImpl.java

package com.liwl.dev;

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

@Component(value = "school")
public class SchoolImpl implements School {

    @Value(value = "江南大学")
    private String name;
    @Value(value = "江苏省无锡市滨湖区蠡湖大道1800号")
    private String address;

    public String getName() {
        return name;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return 
            "name:"+name
            +","+
            "address:"+address
            ;
    }
}
name:liwanliang,age:30,schoolname:江南大学,address:江苏省无锡市滨湖区蠡湖大道1800号

上面代码中,通过@Component注解了LiwanLiangImpl和SchoolImpl,也就是向Spring容器注册bean:LiwanLiangImpl和SchoolImpl,其bean的id是"liwl"和"school",而LiwanLiangImpl和SchoolImpl的属性值name和age,通过@Value来注解。在LiwanLiangimpl里面的School属性,则是通过注解@Autowire+@Qualifiler实现按照名称自动注入

4.3 引入外部属性文件

假如我们是通过外部配置文件来设置数据库,我们没有必要把数据库相关配置数据写入源码,从而解耦数据库的相关信息。那我们可以通过以下方式来解耦。

以外部配置文件来配置实现类的初始值

修改springdi.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.xsd 
        http://www.springframework.org/schema/context 
        https://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- 注册扫描器 -->
    <context:component-scan base-package="com.liwl.dev"/>
    <!-- 引入外部属性配置文件 -->
    <context:property-placeholder location="classpath:all.properties" file-encoding="utf-8"/>

</beans>

在目录下创建all.properties文件,内容

liwl_name="liwanliang001"
liwl_age=30
school_name="江南大学001"
school_address="江苏省无锡市滨湖区蠡湖大道1800号001"

修改LiwanLiangImpl.java

package com.liwl.dev;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component(value = "liwl")
public class LiwanLiangImpl implements LiwanLiang {
    
    @Value(value = "${liwl_name}")
    private String name;
    @Value(value = "${liwl_age}")
    private int age;
    @Autowired
    private School school;

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

    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }

    public School getSchool() {
        return school;
    }

    public void setSchool(School school) {
        this.school = school;
    }


    @Override
    public String toString() {
        return 
            "name:"+name
            +","+
            "age:"+age
            +","+
            "school"+school
            ;
    }
}

修改SchoolImpl.java

package com.liwl.dev;

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

@Component(value = "school")
public class SchoolImpl implements School {

    @Value(value = "${school_name}")
    private String name;
    @Value(value = "${school_address}")
    private String address;

    public String getName() {
        return name;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return 
            "name:"+name
            +","+
            "address:"+address
            ;
    }
}

运行结果

name:"liwanliang001",age:30,schoolname:"江南大学001",address:"江苏省无锡市滨湖区蠡湖大道1800号001"

总结一下:

在springdi.xml里面添加了<context:property-placeholder location="classpath:all.properties" file-encoding="utf-8"/>,如此以来无论是在LiwanLiangImpl.java还是SchoolImpl.java里面,@Value的注解默认值就可以通过${xxx}的方式,引入all.properties的值。所以此配置是全局的

再来使用注解代替XML配置

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

    <!-- 注册扫描器 -->
    <context:component-scan base-package="com.liwl.dev"/>

</beans>

修改LiwanLiangImpl.java

package com.liwl.dev;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@PropertySource(value = {"classpath:all.properties"},encoding = "utf-8")
@Component(value = "liwl")
public class LiwanLiangImpl implements LiwanLiang {
    
    @Value(value = "${liwl_name}")
    private String name;
    @Value(value = "${liwl_age}")
    private int age;
    @Autowired
    private School school;

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

    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }

    public School getSchool() {
        return school;
    }

    public void setSchool(School school) {
        this.school = school;
    }

    @Override
    public String toString() {
        return 
            "name:"+name
            +","+
            "age:"+age
            +","+
            "school"+school
            ;
    }
}

运行结果

name:"liwanliang003",age:30,schoolname:"江南大学003",address:"江苏省无锡市滨湖区蠡湖大道1800号003"

注:SchoolImpl.java不需要添加@PropertySource注解,它通过Component注册到Spring容器

到目前发现spring.xml已经只剩下<context:component-scan base-package="com.liwl.dev"/>标签

接下来就是把该标签也变成注解

5. 全注解方式注入

在目录/root/liwl_dev/java/web/spring/SpringDI/src/main/java/com/liwl/dev下,创建配置类源文件SpringDIConfig.java

package com.liwl.dev;

import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Configuration
@ComponentScan(value={"com.liwl.dev"})
public class SpringDIConfig {
   private String info = "我是spring配置类";
   public void showMe(){
       System.out.println(info);
   }
}

修改MyTest.java文件

package com.liwl.dev;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class LiwlTest {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringDIConfig.class);
        SpringDIConfig config = context.getBean(SpringDIConfig.class);
        config.showMe();
        ((ConfigurableApplicationContext) context).close();
    }
}

运行结果

我是spring配置类

说明Spring已经加载了配置类,实例化配置类以后,调用了它的方法

修改MyTest.java

package com.liwl.dev;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class LiwlTest {
    public static void main(String[] args) {

        ApplicationContext context = new AnnotationConfigApplicationContext(SpringDIConfig.class);
        LiwanLiangImpl liwl = (LiwanLiangImpl) context.getBean("liwl");
        System.out.println(liwl);
        ((ConfigurableApplicationContext) context).close();
    }
}

运行结果

name:"liwanliang003",age:30,schoolname:"江南大学003",address:"江苏省无锡市滨湖区蠡湖大道1800号003"

6. 总结

本篇主要介绍了使用Spring框架开发时,如何通过XML配置bean,然后注册到Spring容器里。XML通过不同的标签来设置对象的属性以及注入方式(set设值注入,构造方法注入),也可以通过标签来引入其他模块的XML配置。当不在XML里面配置bean时,通过

<context:component-scan base-package="com.liwl.dev"/>
<context:property-placeholder location="classpath:all.properties" file-encoding="utf-8"/>

指定要扫描的包以及属性配置文件,然后Spring就能够通过注解的方式代替XML拿到bean配置的属性值,同时通过注解来自动加载需要注入的bean。

最后可以创建配置类,通过注解完全代替XML的配置。

posted @ 2022-02-22 10:37  liwldev  阅读(60)  评论(0编辑  收藏  举报