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和注解同时存在。
本篇博客参考以下博客内容:
- https://bbs.huaweicloud.com/blogs/327394
- https://bbs.huaweicloud.com/blogs/327710
- 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的配置。