依赖注入的方式有setter注入、构造器注入、自动装配、集合注入
首先,Maven项目pom.xml依赖包如下:
pom.xml
<?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>org.example</groupId>
<artifactId>spring-1</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.22.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
</dependencies>
</project>
【注】:上述除spring依赖包之外其他三个依赖包用于测试使用。
1. setter注入
先说明一下,这里有的文件为Book2Dao(接口)、Book2DaoImpl(Book2Dao接口实现类)、Book2Service(接口)、Book2ServiceImpl(Book2Service即可实现类)、Test2(用于测试)。示例在Book2ServiceImpl类中使用Book2Dao的方法save,如下:
Book2Dao
package com.bh.dao;
public interface Book2Dao {
void save();
}
Book2DaoImpl
package com.bh.dao.Impl;
import com.bh.dao.Book2Dao;
public class Book2DaoImpl implements Book2Dao {
public void save() {
System.out.println(" Book2DaoImpl 已保存数据!");
}
}
Book2Service
package com.bh.service;
public interface Book2Service {
void save();
}
Book2ServiceImpl
package com.bh.service.Impl;
import com.bh.dao.Book2Dao;
import com.bh.service.Book2Service;
public class Book2ServiceImpl implements Book2Service {
private Book2Dao book2Dao;
public void setBook2Dao(Book2Dao book2Dao) {
this.book2Dao = book2Dao;
}
public void save() {
book2Dao.save();
}
}
applicationContext.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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 开启context的命名空间 -->
<bean id="book2Dao" class="com.bh.dao.Impl.Book2DaoImpl"/>
<bean id="book2Service" class="com.bh.service.Impl.Book2ServiceImpl">
<property name="book2Dao" ref="book2Dao"/>
</bean>
</beans>
【注】:这个xml文件是开启了context的命名空间的,用于后续操作。
Test2
package com.bh;
import com.bh.service.Book2Service;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test2 {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Book2Service book2Service = ctx.getBean("book2Service", Book2Service.class);
book2Service.save();
}
}
运行结果为:
这种方式如果在Book2ServiceImpl类中引入多个其他类的依赖时,在配置文件applicationContext.xml上就需要写上对应的property标签,并且一旦Java类上这些引入的依赖变量名称进行修改,对应的配置文件bean标签里的property标签也要进行相应的修改,显得很繁琐,有没有简便的方法呢?有的,那就是使用自动装配。
自动装配
只需要修改一下applicationContext.xml配置文件即可。
applicationContext.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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 开启context的命名空间 -->
<bean id="book2Dao" class="com.bh.dao.Impl.Book2DaoImpl"/>
<bean id="book2Service" class="com.bh.service.Impl.Book2ServiceImpl" autowire="byType"/>
</beans>
运行结果和上述一样。
如果在上述applicationContext.xml定义了两个Book2DaoImpl类型相同的bean,则会报错,如下:
运行结果:
从报错信息上分析,是因为我定义了两个class类型相同的bean,而使用的自动装配方式是按类型(byType)进行装配的,我可以修改一下自动装配类型,使用byName按名称,这样就没有问题了,如下:
这样修改之后,就能正常运行出结果了。但是使用按名称进行装配,对于bean的id值是有要求的,id值需要与Java类上对应变量名称一致,否则也会出问题。
对于自动装配,总结如下:
- 自动装配用于引用类型依赖注入,不能对简单类型进行操作;
- 使用按类型装配时,必须保障容器中相同类的bean唯一,推荐使用;
- 使用按名称装配时,必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用;
- 自动装配优先级低于setter注入与构造器的注入,同时出现时自动装配失效。
2. 构造器注入
使用构造方法进行注入,原Book2ServiceImpl类修改为:
Book2ServiceImpl
package com.bh.service.Impl;
import com.bh.dao.Book2Dao;
import com.bh.service.Book2Service;
public class Book2ServiceImpl implements Book2Service {
private Book2Dao book2Dao;
public Book2ServiceImpl(Book2Dao book2Dao) {
this.book2Dao = book2Dao;
}
public void save() {
book2Dao.save();
}
}
上述applicationContext.xml配置文件修改为如下:
运行结果同上述正常运行结果;
如果构造方法中有简单类型,constructor-arg标签如下:
<constructor-arg name="name" value="liuze"/>
但是这种方式一旦Java类变量名称修改了,配置文件也需要进行相应的名称修改,可以把name属性去掉,用index来代替,index值从0开始,表示Java类构造方法中形参的位置。
3. 集合注入
比如在一个Java类中有一些集合类型的变量,如数组、List、Set、Map、Properties,参考示例如下(使用setter注入):
RandomObject
package com.bh.other;
import java.util.*;
public class RandomObject {
private int[] arrObj;
private List<String> listObj;
private Set<String> setObj;
private Map<String,String > mapObj;
private Properties propertiesObj;
public void setArrObj(int[] arrObj) {
this.arrObj = arrObj;
}
public void setListObj(List<String> listObj) {
this.listObj = listObj;
}
public void setSetObj(Set<String> setObj) {
this.setObj = setObj;
}
public void setMapObj(Map<String, String> mapObj) {
this.mapObj = mapObj;
}
public void setPropertiesObj(Properties propertiesObj) {
this.propertiesObj = propertiesObj;
}
public void save(){
System.out.println("保存数据。。。");
System.out.println(Arrays.toString(arrObj));
System.out.println(listObj);
System.out.println(setObj);
System.out.println(mapObj);
System.out.println(propertiesObj);
}
}
在applicationContext.xml配置文件为:
<bean id="randomObject" class="com.bh.other.RandomObject">
<property name="arrObj">
<array>
<value>123</value>
<value>456</value>
<value>789</value>
</array>
</property>
<property name="listObj">
<list>
<value>abc</value>
<value>efg</value>
<value>hij</value>
</list>
</property>
<property name="setObj">
<set>
<value>abc</value>
<value>efg</value>
<value>hij</value>
<value>abc</value>
</set>
</property>
<property name="mapObj">
<map>
<entry key="name" value="liuze"/>
<entry key="age" value="22"/>
<entry key="address" value="hunan"/>
</map>
</property>
<property name="propertiesObj">
<props>
<prop key="name">liuze</prop>
<prop key="age">23</prop>
<prop key="address">hunan</prop>
</props>
</property>
</bean>
运行结果:
怎样利用上述知识对数据源对象进行注入呢?
applicationContext.xml
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc::mysql://localhost:3306/d_test"/>
<property name="user" value="root"/>
<property name="password" value="sxx123"/>
</bean>
依旧使用setter注入方式即可,那么怎样加载自定义的properties文件呢?这就是说到开头讲的那个aplicationContext.xml文件了,是不是发现这个文件开头那个看不懂的链接比默认的多了几个,那是用于开启context命名空间的。
现在在resources文件夹有一个jdbc.properties文件如下:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc::mysql://localhost:3306/d_test
jdbc.username=root
jdbc.password=sxx123
在aplicationContext.xml如何读取这些数据,如下:
运行结果: