Spring IoC 通过 DI 注入的三种常用方式
- 构造器注入
- set注入
- 注解注入(自动注入)
注入方式不止这几种,这里主要列举常用的三种注入方式整理及个人学习总结, 其他注入方式并未列出,如有侵权或错误,请指认留言,在此表示感谢!
01_构造方法注入
- 使用类中的构造函数,给成员变量(简单类型、javaBean)赋值
1. 提供对应的构造方法,如下:
public class User {
/*
* 配置构造方法的参数
* */
private int id;
private String username;
private String password;
/*
* 提供对应的构造方法
* */
public User() {}
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
/*
* 打印输出
* */
public void Test(){
System.out.println("id="+id);
System.out.println("username="+username);
System.out.println("password="+password);
}
}
2. spring.xml配置文件
<!--构造器-->
<bean id="user" class="cn.tzgod.bean.User">
<constructor-arg name="id" value="1"/>
<constructor-arg name="username" value="tzgod"/>
<constructor-arg name="password" value="123"/>
</bean>
- 测试代码
/*
*构造方法注入
* */
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User user = applicationContext.getBean(User.class,"user");
user.Test();
/*
* 输出结果:
* id=1
* username=tzgod
* password=123
* */
- 当出现了重载构造方法,并且仅仅是参数的顺序不同,那么配置的时候需要配置index来确认顺序type属性表示参数的类型
/*
* 提供对应的构造方法
* */
public User() {}
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
/*
* 提供重载构造方法
* */
public User(String password, String username ,int id ) {
this.id = id;
this.username = username;
this.password = password;
}
2. spring.xml配置文件
<!--使用重载之前的构造方法-->
<bean id="user" class="cn.tzgod.bean.User">
<constructor-arg name="id" value="1" index="0"/>
<constructor-arg name="username" value="tzgod" index="1"/>
<constructor-arg name="password" value="123" index="2"/>
</bean>
<!--使用重载的构造方法-->
<bean id="user" class="cn.tzgod.bean.User">
<constructor-arg name="id" value="1" index="2"/>
<constructor-arg name="username" value="tzgod" index="1"/>
<constructor-arg name="password" value="123" index="0"/>
</bean>
02_Set方法注入
- 在对某个类中提供所需对象属性时,是通过其提供的set方法注入给成员变量(简单类型、javaBean)赋值,而不是直接通过属性名称注入的
- 创建一个set方法,如下:
public class User {
/*
* 配置构造方法的参数
* */
private int id;
private String username;
private String password;
/**
* 通过Set方法完成依赖注入
*/
public void setId(int id){
this.id = id ;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
/**
* 提供toString方法
*/
@Override
public String toString() {
return "toString{" +
"id='" + id + '\'' +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
- 配置spring.xml注入
注入的值有两种方式:
- 一种叫value,表示基本数据类型和字符串的设置。
- 一种叫ref,表示引用其他对象(构造方法中也可以使用)
- value方式
<!--配置spring.xml-->
<bean id="set" class="cn.tzgod.bean.User" >
<!--通过set方法注入-->
<property name="id" value="1"/>
<property name="username" value="tzgod"/>
<property name="password" value="123"/>
</bean>
/*
*测试方法
* */
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User user = applicationContext.getBean(User.class,"set");
System.out.println(user);
/*
*输出结果:
*toString{id='1'username='tzgod', password='123'}
* */
- ref方式
/*
*创建User对象
*/
public class Users {
private User user;
public void setUser(User user) {
this.user = user;
}
/*输出user*/
public void say(){
System.out.println("User:" + user );
}
}
<!--配置spring.xml-->
<bean id="set" class="cn.tzgod.bean.User" >
<!--通过set方法注入-->
<property name="id" value="1"/>
<property name="username" value="tzgod"/>
<property name="password" value="123"/>
</bean>
<bean id="user2" class="cn.tzgod.bean.Users" >
<!--通过set方法注入-->
<property name="user" ref="set"></property>
</bean>
/*
*测试方法
* */
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Users users = applicationContext.getBean(Users.class,"user2");
users.say();
/*
*输出结果:
*User:toString{id='1'username='tzgod', password='123'}
* */
03_注解注入
由于spring的核心就是一个工厂,pring利用IoC+工厂模式这一套解耦的设计理念,用Spring对象工厂+DI进行自动注入,这里只简单的介绍下注解的作用
- 主要有四种注解可以注册bean,作用于类上,用来表示将当前的类交给Spring进行管理(创建对象、注入对象),很多时候可以
随便用(不建议)。
@Controller : 一般用在控制器上
@Service : 一般用在业务层
@Repository : 一般用在DAO上
@Component : 一般用在其他任何位置(默认ID是当前类的首字母小写,同时也可以在@Component注解的参数中指定ID)
- 主要以以下注解进行自动装配
- @Autowired : 作用于方法上,用来表示当前方法需要被注入一个对象 , 在所有需要注入的属性上加上@Autowired注解,甚至可以不写set方法
- @Resource : 作用于方法上, 优先通过byName查找属性名相同的bean的名字,找不到才从byType查找属性相同的bean的属性
- @Bean : 作用于方法上,用来表示此方法提供一个对象
- @Qualifier : 作用于方法上,用来表示当前注入一个指定名称的对象,当同类型的对象有多个,并且了变量的名称不匹配任何的对象,则可以通过Qualifier注解指定注入哪个对象。一般情况Qualifier和Autowired是配合使用。
- @Configuration : 作用于类上,用来表示当前类为Spring的初始化配置类(入口类)
- @ComponentScan : 作用于类上,一般和Configuration 一起使用,用来表示Spring需要管理的类在哪一个包下
- spring中使用注解
在Spring配置文件中添加扫描的路径:
<!-- 扫描的路径为项目路径 -->
<context:component-scan base-package="cn.tzgod"></context:component-scan>
实际上开发的时候自己编写的类一般用注解的方式注册类,用@Autowired描述依赖进行注入也可以用@Resource自动注入功能,两者之间没什么太大差别,主要区别就是@Autowired是默认按照类型装配的 @Resource默认是按照名称装配的
附:
_复杂类型注入
- 对于数组,List或Set类型,当元素只有一个时,可以直接使用value或ref,
- 当有多个元素时,set,array,list标签可以互换,用的也是set方法注入的方式,只不过变量的数据类型都是集合。
- Map和Properties才需要单独特殊处理。
public class MyData {
private Object [] arr;
private List list;
private Map map;
private Set set;
private Properties prop;
public void setArr(Object[] arr) {
this.arr = arr;
}
public void setList(List list) {
this.list = list;
}
public void setMap(Map map) {
this.map = map;
}
public void setSet(Set set) {
this.set = set;
}
public void setProp(Properties prop) {
this.prop = prop;
}
@Override
public String toString() {
return "MyData{" +
"arr=" + Arrays.toString(arr) +
", list=" + list +
", map=" + map +
", set=" + set +
", prop=" + prop +
'}';
}
}
<bean id="myData" class="cn.tzgod.bean.MyData">
<property name="arr">
<array>
<value>arr1</value>
<value>arr2</value>
<array>
</property>
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
<list>
</property>
<property name="map">
<map>
<entry key="a" value="1111" value-type="java.lang.Integer"></entry>
<entry key="c" value="mapc" ></entry>
</map>
</property>
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
</set>
</property>
<property name="prop">
<props>
<prop key="aaa">prop1</prop>
<prop key="bbb">prop2</prop>
</props>
</property>
</bean>
_p空间和spEL注入
-
p空间:
- 是注入是一种简写的办法
- 首先需要引入p空间,在配置文件中添加p空间的引入:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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.xsd">
- 配置文件中如下配置:
<bean id="set" class="cn.tzgod.bean.User" >
<property name="id" value="1"/>
<property name="username" value="tzgod"/>
<property name="password" value="123"/>
</bean>
<!--上面的写法简写为下面的写法:-->
<bean id="set" class="cn.tzgod.bean.User"
p:id="1" p:username="tzgod" p:password="123" >
</bean>
-
spEL:
- spEL是指在引用时使用表达式。#{}表示引用其他对象,${}表示引用其他文件中的内容。
- 添加一个 . properties配置文件 : myconfig . properties
c.id=1
c.username=tzgod
c.password=123
- 配置文件中如下配置:
<bean id="c" class="cn.tzgod.bean.User">
<property name="id" value="1"/>
<property name="username" value="tzgod"/>
<property name="password" value="123"/>
</bean>
<!-- 下面表示表示引用properties配置文件 -->
<context:property-placeholder location="classpath:myconfig.properties"></context:property-placeholder>
<bean id="set" class="cn.tzgod.bean.User">
<property name="id" value="#{c.id}"/>
<property name="username" value="#{c.username}"/>
<property name="password" value="#{c.password}"/>
</bean>
_多配置文件加载
- 在主配置文件(spring.xml)中导入子配置文件
<import resource="spring01.xml"/>
<import resource="spring02.xml"/>
<import resource="spring03.xml"/>
-
格式一:
- 加载ApplicatioContext对象时需要加载主配置文件即可
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
-
格式二:
- 一次性加载多个配置文件(可变参数对象格式)
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"spring01.xml","spring02.xml","spring03.xml");
-
格式三:
- 一次性加载多个配置文件(数组对象格式)
ApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[]{"spring01.xml","spring02.xml","spring03.xml"})
注意事项
- 配置冲突问题,后生效的配置覆盖之前的配置!