Spring IOC的四种注入方法
Spring ?持的注??式共有四种:set 注?、构造器注?、静态??注?、实例化??注?
注:注入前提均建立在建立好的spring环境内
1.Set方法注入-五种类型的注入
以业务对象JavaBean为主
1.1 业务对象JavaBean
第一步:创建dao包下的UserDao类
package com.svt.dao;
public class UserDao {
public void test(){
System.out.println("UserDao Test...");
}
}
第二步:属性字段提供set?法
原先写的方式都是手动实例化,比如private UserDao userDao=new UserDao();
,这样会耦合过高,所以我们采用了新的形式:注入
package com.svt.service;
import com.svt.dao.UserDao;
public class UserService {
//手动实例化
//private UserDao userDao=new UserDao();
//业务逻辑对象JavaBean 提供set方法注入
//在配置文件中还未告知set方法注入 所以userDao是空的
//将这里bean对象实例化的过程交给IOC去做
private UserDao userDao;
//set方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void test(){
System.out.println("UserService Test...");
userDao.test();
}
}
第三步:配置?件的bean标签设置property标签
通过property属性实现注入
<?xml version="1.0" encoding="UTF-8"?>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
Set方法注入
通过property属性注入
-->
<bean id="userService" class="com.svt.service.UserService">
<!--
name:bean对象中属性字段的名称
ref:指定bean标签的id属性值
-->
<property name="userDao" ref="userDao" />
</bean>
<bean id="userDao" class="com.svt.dao.UserDao"></bean>
</beans>
如果没有在资源文件夹xml内通过property属性实现注入,那么会出现空指针异常
第四步:测试
在UserService类中写测试方法
public void test(){
System.out.println("UserService Test...");
//JavaBean对象
userDao.test();
}
再在测试类中调用
import com.svt.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter01 {
public static void main(String[] args) {
//获取Spring的上下文环境 BeanFactory也是可以的
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
UserService userService= (UserService) ac.getBean("userService");
userService.test();
}
}
出现测试类中展现的内容则代表注入无误
1.2 常用对象String(日期类型)| 基本类型Integer
第一步:属性字段提供 set ?法
//常用对象String(日期类型)
private String host;
public void setHost(String host) {
this.host = host;
}
//基本类型 Integer
private Integer port;
public void setPort(Integer port) {
this.port = port;
}
第二步:配置?件的 bean 标签设置 property 标签
<!-- value:具体的值(基本类型 常用对象|日期 集合)-->
<!-- 常用对象 String-->
<property name="host" value="127.0.0.1"/>
<!-- 基本类型Integer-->
<property name="port" value="8080"/>
第三步:测试
在UserService类中写测试方法
public void test(){
System.out.println("UserService Test...");
//常用对象
System.out.println(host);
//基本类型
System.out.println(port);
}
再在测试类中调用
import com.svt.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter01 {
public static void main(String[] args) {
//获取Spring的上下文环境 BeanFactory也是可以的
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
UserService userService= (UserService) ac.getBean("userService");
userService.test();
}
}
出现测试类中展现的内容则代表注入无误
1.3 集合类型和属性对象
第一步:属性字段提供set?法
//List集合
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
//List输出
public void printList(){
list.forEach(v-> System.out.println(v));//jdk8提供
}
//Set集合
private Set<String> sets;
public void setSets(Set<String> sets) {
this.sets = sets;
}
//Set输出
public void printSet(){
sets.forEach(v-> System.out.println(v));
}
//Map集合
private Map<String,Object> map;
public void setMap(Map<String, Object> map) {
this.map = map;
}
//Map输出
public void printMap(){
map.forEach((k,v)-> System.out.println(k+"="+v));
}
//Properties属性对象
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
//Properties输出
public void printProperties(){
properties.forEach((k,v)-> System.out.println(k+"="+v));
}
第二步:配置?件的bean标签设置property标签
<!-- List集合-->
<property name="list">
<list>
<value>江苏</value>
<value>浙江</value>
<value>上海</value>
</list>
</property>
<!-- Set集合-->
<property name="sets">
<set>
<value>江苏JS</value>
<value>浙江ZJ</value>
<value>上海SH</value>
</set>
</property>
<!-- Map集合-->
<property name="map">
<map>
<entry>
<key>
<value>周杰伦</value>
</key>
<value>晴天</value>
</entry>
<entry>
<key>
<value>林俊杰</value>
</key>
<value>美人鱼</value>
</entry>
<entry>
<key>
<value>陈奕迅</value>
</key>
<value>富士山下</value>
</entry>
</map>
</property>
<!-- Properties属性对象-->
<property name="properties">
<props>
<prop key="js">江苏</prop>
<prop key="zj">浙江</prop>
<prop key="sh">上海</prop>
</props>
</property>
第三步:测试
与上面一样
public void test(){
System.out.println("UserService Test...");
//List集合类型
printList();
//Set集合类型
printSet();
//Map集合类型
printMap();
//Properties属性对象
printProperties();
}
2.构造器方法注入-种形式的注入
2.1 单个Bean对象作为参数
第一步:JavaBean对象
package com.svt.service;
import com.svt.dao.UserDao02;
/**
* 构造器方法注入
* 需要提供带参构造
*/
public class UserService02 {
private UserDao02 userDao02;
/* 构造器注入*/
public UserService02(UserDao02 userDao02) {
this.userDao02 = userDao02;
}
public void test(){
System.out.println("UserService Test...");
}
}
第二步: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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
构造器注入
设置构造器所需要的参数
通过constructor-arg标签设置构造器的参数
name:属性名称
ref:要注入的bean对象对应的bean标签的id属性值
-->
<bean id="userService02" class="com.svt.service.UserService02">
<constructor-arg name="userDao02" ref="userDao02"></constructor-arg>
</bean>
<bean id="userDao02" class="com.svt.dao.UserDao02"></bean>
</beans>
第三步:测试
import com.svt.service.UserService02;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter02 {
public static void main(String[] args) {
//获取Spring的上下文环境 BeanFactory也是可以的
ApplicationContext ac=new ClassPathXmlApplicationContext("spring02.xml");
UserService02 userService02= (UserService02) ac.getBean("userService02");
userService02.test();
}
}
出现测试类中展现的内容则代表注入无误
2.2 多个Bean对象作为参数
第一步:JavaBean对象
package com.svt.service;
import com.svt.dao.UserDao;
import com.svt.dao.UserDao02;
/**
* 构造器方法注入
* 需要提供带参构造
*/
public class UserService02 {
private UserDao02 userDao02;
/* 构造器注入*/
/*public UserService02(UserDao02 userDao02) {
this.userDao02 = userDao02;
}*/
private UserDao userDao;
public UserService02(UserDao02 userDao02, UserDao userDao) {
this.userDao02 = userDao02;
this.userDao = userDao;
}
public void test(){
System.out.println("UserService Test...");
userDao02.test();
userDao.test();
}
}
第二步: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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
构造器注入
设置构造器所需要的参数
通过constructor-arg标签设置构造器的参数
name:属性名称
ref:要注入的bean对象对应的bean标签的id属性值
value:数据具体的值
index:参数的位置(从0开始)一般不用 但是可以确定参数是哪个位置的
-->
<bean id="userService02" class="com.svt.service.UserService02">
<constructor-arg name="userDao02" ref="userDao02"></constructor-arg>
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
<bean id="userDao02" class="com.svt.dao.UserDao02"></bean>
<bean id="userDao" class="com.svt.dao.UserDao"></bean>
</beans>
如果在写完JavaBean对象而没有在配置文件中添加bean则会出现以下报错内容,像上面xml文件中一样添加 <constructor-arg name="userDao" ref="userDao"></constructor-arg>
即可
第三步:测试
在UserService02中的test测试方法中新增了两行输出语句
public void test(){
System.out.println("UserService Test...");
userDao02.test();
userDao.test();
}
出现测试类中展现的内容则代表注入无误
2.3 Bean对象和常?对象作为参数
第一步:加入常用对象String(举例)
private UserDao02 userDao02;
/* 构造器注入*/
private UserDao userDao;
private String user;
public UserService02(UserDao02 userDao02, UserDao userDao, String user) {
this.userDao02 = userDao02;
this.userDao = userDao;
this.user = user;
}
第二步: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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
构造器注入
设置构造器所需要的参数
通过constructor-arg标签设置构造器的参数
name:属性名称
ref:要注入的bean对象对应的bean标签的id属性值
value:数据具体的值
index:参数的位置(从0开始)一般不用 但是可以确定参数是哪个位置的
-->
<bean id="userService02" class="com.svt.service.UserService02">
<constructor-arg name="userDao02" ref="userDao02"></constructor-arg>
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
<constructor-arg name="user" value="user" index=""></constructor-arg>
</bean>
<bean id="userDao02" class="com.svt.dao.UserDao02"></bean>
<bean id="userDao" class="com.svt.dao.UserDao"></bean>
</beans>
第三步:测试
在UserService02中的test测试方法中新增了一行输出语句
public void test(){
System.out.println("UserService Test...");
userDao02.test();
userDao.test();
System.out.println(user);
}
出现测试类中展现的内容则代表注入无误
2.4 循环依赖问题
产生原因:Bean 通过构造器注?,之间彼此相互依赖对?导致 bean ?法实例化。比如一个IOC容器要去实例化A,但是A中有B的注入,于是IOC就先去找B实例化,此时B中又有A的注入,IOC又要去找A先进行初始化,这样一套下来IOC不知道是先找A还是B就会出现循环依赖的问题。
问题示例
- 代码示例
public class AccountService {
private AccountDao accountDao;
public AccountService(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void test(){
System.out.println("AccountService Test...");
accountDao.test();
}
}
public class AccountDao {
private AccountService accountService;
public AccountDao(AccountService accountService) {
this.accountService = accountService;
}
public void test(){
System.out.println("AccountDao Test...");
}
}
- 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 循环依赖问题-->
<bean id="acountService" class="com.svt.service.AccountService">
<constructor-arg name="accountDao" ref="accountDao"></constructor-arg>
</bean>
<bean id="accountDao" class="com.svt.dao.AccountDao">
<constructor-arg name="accountService" ref="acountService"></constructor-arg>
</bean>
</beans>
此时AccountDao 注入了AccountService ,而AccountService 也注入了AccountDao ,这就造成了循环依赖
问题解决
如果出现循环依赖 需要通过set注入解决,下面就依据上面的循环注入代码进行解决
- 解决代码示例
public class AccountDao {
private AccountService accountService;
public void setAccountService(AccountService accountService) {
this.accountService = accountService;
}
public void test(){
System.out.println("AccountDao Test...");
}
}
public class AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void test(){
System.out.println("AccountService Test...");
accountDao.test();
}
}
- 解决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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 如果出现循环依赖 需要通过set注入解决-->
<bean id="accountService" class="com.svt.service.AccountService">
<property name="accountDao" ref="accountDao"></property>
</bean>
<bean id="accountDao" class="com.svt.dao.AccountDao">
<property name="accountService" ref="accountService"></property>
</bean>
<!--
构造器必须等待构造器参数中的实例化实例化好后才会实例化本身
set方法注入:先实例化对象,再找被注入的set进去,就不会造成循环依赖
-->
</beans>
原因
- 构造器注入:必须等待构造器参数中的实例化实例化好后才会实例化本身
- set方法注入:先实例化对象,再找被注入的set进去,就不会造成循环依赖
3.静态工厂注入(了解)
第一步:创建工厂类
new factory->new StaticFactory
package com.svt.factory;
import com.svt.dao.TypeDao;
//静态工厂
public class StaticFactory {
//定义静态方法
public static TypeDao createTypeDao(){
return new TypeDao();
}
}
第二步:创建dao实体类
package com.svt.dao;
public class TypeDao {
public void test(){
System.out.println("TypeDao Test...");
}
}
第三步:创建TypeService,注入TypeDao
package com.svt.service;
import com.svt.dao.TypeDao;
public class TypeService {
//注入TypeDao
private TypeDao typeDao;
public void setTypeDao(TypeDao typeDao) {
this.typeDao = typeDao;
}
public void test(){
System.out.println("TypeService Test...");
typeDao.test();
}
}
第四步: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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 静态工厂-->
<!-- 定义bean对象-->
<bean id="typeService" class="com.svt.service.TypeService">
<property name="typeDao" ref="typeDao"></property>
</bean>
<!-- 静态工厂注入:通过静态构造实例化需要被注入的bean对象-->
<bean id="typeDao" class="com.svt.factory.StaticFactory" factory-method="createTypeDao"></bean>
</beans>
第五步:测试
import com.svt.service.TypeService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter02 {
public static void main(String[] args) {
//获取Spring的上下文环境 BeanFactory也是可以的
ApplicationContext ac=new ClassPathXmlApplicationContext("spring02.xml");
TypeService typeService= (TypeService) ac.getBean("typeService");
typeService.test();
}
}
出现测试类中展现的内容则代表注入无误
4.实例化工厂注入(了解)
实例化工厂注入与静态工厂注入大致一样,有以下几点不同
4.1 定义实例化工厂,写非静态方法
静态工厂里写的是静态方法,实例化工厂里写的非静态方法
package com.svt.factory;
import com.svt.dao.TypeDao;
//定义实例化工厂
public class InstanceFactory {
public TypeDao createTypeDao(){
return new TypeDao();
}
}
4.2 修改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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 定义bean对象-->
<bean id="typeService" class="com.svt.service.TypeService">
<property name="typeDao" ref="typeDao"></property>
</bean>
<!-- 实例化工厂注入:通过实例化工厂需要被注入的bean对象-->
<bean id="instanceFactory" class="com.svt.factory.InstanceFactory"></bean>
<bean id="typeDao" factory-bean="instanceFactory" factory-method="createTypeDao"></bean>
</beans>
其余与静态工厂一致,测试类实现结果也与静态工厂一致
静态工厂注入与实例化工厂注入本质上还是set注入,只是本来bean对象是通过构造器去实例化的,现在更换了以下,想要静态工厂注入就把实例化的方式变成静态工厂,实例化工厂同理,两者用的不多,理解即可
注入方式的选择
开发项?中set?式注??选
使?构造注?可以在构建对象的同时?并完成依赖关系的建?,对象?建?则所有的?切也就准备好
了,但如果要建?的对象关系很多,使?构造器注?会在构建函数上留下??串的参数,且不易记忆,这时使?Set注?会是个不错的选择。
使?Set注?可以有明确的名称,可以了解注?的对象会是什么,像setXXX()这样的名称会?记忆Constructor上某个参数的位置代表某个对象更好。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!