1、我的上一篇博文
2、本篇博客的背景和目的
目前我本人正在学习SpringFramework的知识,这也是这个专栏的主题。我前面的几篇博文中,简单的认识了一下SpringFramework,记录了SpringFramework的环境搭建,记录了SpringIOC如何加载配置文件,记录了SpringIOC三种Bean对象的实例化方法。本篇博客我记录一下SpringIOC手动注入的方法。其实目前大部分都使用的是自动注入的方法,手动注入使用的不多。
3、什么是注入呢?
首先看一张图吧:
在上面的这张图中,我们在UserService类中使用UserDao对象,这就是注入。可以称为:将UserDao注入到UserService中。
无论是手动设置注入,还是后面我会记录到的自动注入,都是要让Spring帮助我们完成类似于上面的工作。
4、手动注入的四种方式
set方法注入,构造器注入,静态工厂注入,实例化工厂注入。
(这是不是跟SpringIOC实例化Bean对象的三种方式有点类似呢?其实是真的很类似)
5、set方法手动注入的逻辑思路
既然使用的是set方法注入,那么就一定会使用到set方法。其次,我们还需要使用到XML配置文件,我们要告诉Spring,具体的对应关系是什么。
下面看两张图片吧,也是例子:
其实逻辑也并不难理解,就是在实体类中写了属性的set方法以后,还需要在XML文件中进行一下配置。然后我们就可以使用getBean()方法,获得已经实例化好的对象。
6、我的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>com.dcy</groupId>
<artifactId>spring04</artifactId>
<version>1.0-SNAPSHOT</version>
<name>spring04</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<!-- 这个是Spring框架的核心依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
上面是我的POM文件,我使用的JDK版本是11的,已经算是比较高的了(17,18这些版本太高了,很多不兼容,不建议使用)。我创建项目的时候使用了一个初始化模板,所以有了下面的插件,其实这些插件不重要,建议读者创建空的Maven项目就可以了。最重要的是两个依赖。其实junit依赖也可以不要,因为这个是测试的依赖,我并没有在测试文件夹中编写代码。
7、我的两个实体类代码
这里我就不展示我的文件结构了,读者随便创建个Maven文件就可以,包的名称和结构随大家调整命名。
第一个实体类:UserDao,这个类是代dao包下面的,比较简单,我只写了一个共有的方法,代码如下:
package com.dcy.dao;
public class UserDao {
public void test(){
System.out.println("UserDao");
}
}
这里UserDao默认使用的构造方法当然就是空构造方法。
第二个实体类:UserService。这个实体类中有一个参数是UserDao对象,并且UserDao对象我写了set方法(
这个是使用set方法注入所必须的,要不然XML文件是会报错的,这也是IDEA这个开发工具的优点
)。代码如下:
package com.dcy.service;
import com.dcy.dao.UserDao;
//import javax.annotation.Resource;
public class UserService {
// @Resource
private UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao=userDao;
}
public void test(){
System.out.println("UserService");
userDao.test();
}
}
这里我多说一下:我上面的代码,在test()方法里面,调用了userDao的test()方法,并且这个UserService类没有构造方法,也就是说,如果我们不使用SpringFramework框架的话,当我们创建一个UserService对象以后,一定要先调用setUserDao方法初始化对象里面的userDao属性对象,然后才能调用UserService对像的test()方法,否则就会报空指针异常!!
8、我的XML文件代码
XML配置文件的代码如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="UserDao" class="com.dcy.dao.UserDao"></bean>
<bean id="UserService" class="com.dcy.service.UserService">
<property name="userDao" ref="UserDao"></property>
</bean>
</beans>
首先我们先写了一个bean标签,将UserDao交给SpringIOC管理,也就是对UserDao使用构造器实例化方法进行实例化。然后下面又是一个bean标签,这个bean标签是将UserService交给了SpringIOC进行管理,使用的也是默认的构造器实例化方法。至于id属性和class属性,这我就不在解释了,本专栏前面几篇博客都介绍过了。然后在第二个bean标签里面,
还嵌套为了一个property标签,这个是本博客的重点
:因为UserService中还有一个UserDao类型的对象属性,因此在我们创建一个UserService类的对象的时候,我们还需要初始化其中的UserDao对象,否则它就是空指针的。这个初始化的过程SpringIOC可以帮助我们完成,但是我们需要告诉SpringIOC具体的关系是什么,也就是需要配置。因此,就有了bean标签里面的property标签。
property标签的name属性值是类中的一个对象参数属性名
,在我们这个例子中,就是属性名:userDao。
ref属性值是在XML文件中,类的属性参数对象所属类在XML文件中对应的bean标签的id属性值
。这两个属性一起,就容易理解了,
也就是告诉SpringIOC,注入的时候,用哪一个类初始化哪一个属性
。
9、进行一下测试
我直接在Main方法里面测试了,代码如下:
package com.dcy;
//import com.dcy.service.AccountService;
import com.dcy.service.UserService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter {
public static void main(String[] args) {
//首先加载配置文件
BeanFactory factory=new ClassPathXmlApplicationContext("spring04.xml");
//仍然是通过getBean()方法获得对应的对象
UserService userService= (UserService) factory.getBean("UserService");
userService.test();
}
}
上面的代码比较简单,就是先加载我们的配置文件,我的配置文件名是:spring04.xml。然后通过getBean()方法获得一个UserService类的对象,最后调用它的test()方法。输出结果如下:
很明显,并没有报空指针异常。是SpringIOC帮助我们在后面做了很多工作。
10、类中属性参数的类型是基本类型怎么办呢?
我们上面简单的示例代码中,使用的是自定义的Bean对象的嵌套,但是,如果类中属性参数的类型是基本类型,我们又该怎么办呢?比如字符串类型,整型(这里统一说的是包装类),甚至是集合呢?
一样的道理,同样还是需要我们写好类中的set()方法。
然后就是修改XML配置文件,说的更具体一点,就是修改property标签。
下面举一个简单的例子,先看我们的实体类代码:
package com.dcy.service;
public class UserService {
// @Resource
private String name;
public void setName(String name){
this.name=name;
}
public void test(){
System.out.println("UserService的名字是"+name);
}
}
里面包含一个属性name,类型是String。如果我们不使用SpringFramework的话,不做配置,那么我们需要先设置其中的name属性值,然后再调用test()方法,否则new出来的UserService对象的name属性值就是null。
下面是XML文件的代码:
<?xml version="1.0" encoding="UTF-8"?>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="UserService" class="com.dcy.service.UserService">
<property name="name" value="口水甜"></property>
</bean>
</beans>
将property标签里面原先的ref属性换成了 value属性。
value属性的值将作为类中参数的值
;这个是比较容易理解的。
下面看一下在Main方法中测试的代码和结果:
package com.dcy;
//import com.dcy.service.AccountService;
import com.dcy.service.UserService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter {
public static void main(String[] args) {
//首先加载配置文件
BeanFactory factory=new ClassPathXmlApplicationContext("spring04.xml");
//仍然是通过getBean()方法获得对应的对象
UserService userService= (UserService) factory.getBean("UserService");
userService.test();
}
}
输出结果如下:
口水甜 三个字被打印出来了,并没有打印null。
但是,如果参数是List类型,Map类型,Set类型的怎么办呢?
当然还是修改property标签,这里我就不粘贴代码了,情况比较多,我直接粘贴具体的截图了,如下所示:
上面分别是XML文件修改的情况,其实:这种基本类型,List,Map使用的不多,不太可能所有的对象,这些属性值都一样,那也没有意义。基本使用的都是最上面列举的注入我们自定义实体类的例子。这个基本类型的做一个了解就好了,不常用的话也记不住,用的时候上网查就好了。
11、总结一下吧
这篇博客记录了使用set方法将一个实体类注入到另一个实体类的情况,需要我们写set()方法,然后修改XML配置文件。属于我们手动注入。还是比较麻烦的。
12、我本专栏的下一篇博客