1.2 依赖注入(Dependency Injection)
依赖注入的数据类型:
- 基本类型和String类型
- bean类型
- 复杂类型/集合类型
依赖注入的三种方式:
- 使用构造函数提供
- 使用set方法提供
- 使用注解方式提供
1.2.1 通过构造函数实现依赖注入
当java类中写了自己的构造函数(如下面所给代码,构造函数有三个参数),则可以通过构造函数的方式实现依赖注入,这个时候需要标签bean中的constructor-arg标签来实现每个参数的赋值。
标签:constructor-arg
属性:
- name:用于给指定构造函数的指定形参赋值
- type:用于给指定构造函数中指定形参类型的形参赋值
- index:用于给指定构造函数中指定索引位置的形参赋值,索引从0开始
- value:用于给基本类型和String类型的形参赋实际值
- ref:用于给其他类型的形参赋实际值(IoC核心容器中定义的bean对象)
下面代码实现了利用构造函数方式完成依赖注入,AccountServiceImpl类有一个有三个参数的构造函数,在bean.xml中配置实现对三个参数赋值,创建AccountServiceImpl类的bean对象。
public class AccountServiceImpl implements IAccountService {
private String name;
private Integer i;
private Date date;
// 构造函数,有三个参数
public AccountServiceImpl(String name, Integer i, Date date) {
this.name = name;
this.i = i;
this.date = date;
}
}
<!-- 通过构造函数来完成注解 -->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<!-- 通过name属性对构造函数中“name”参数进行赋值(String类型) -->
<constructor-arg name="name" value="hugh"></constructor-arg>
<!-- 通过type属性对构造函数中参数类型为Integer的参数进行赋值(基本类型) -->
<constructor-arg type="java.lang.Integer" value="23"></constructor-arg>
<!-- 通过index属性对构造函数中第2个参数进行赋值(bean对象),并利用ref属性引用其他bean对象 -->
<constructor-arg index="2" ref="date_now"></constructor-arg>
</bean>
<bean id="date_now" class="java.util.Date"></bean>
需要注意,基本类型和String类型可直接通过value属性赋值,bean类型需要通过ref属性来引用IoC容器中的其他bean对象,而复杂类型/集合类型不可以通过value或ref属性进行赋值,也就是复杂类型/集合类型不可通过构造函数注入(在1.2.2节中说明)。
1.2.2 通过set方法实现依赖注入
上面已经指出,复杂类型/集合类型不可通过构造函数注入,所以需要通过set方法注入。下面代码中的AccountServiceImpl类有5个复杂类型的类成员,对应有5个set方法,在bean.xml中用标签bean中的property标签,来对这5个类成员进行赋值。
标签:property
属性:
- name:需要与set方法名一致,用于指定set方法
property中的标签:array, list, set, map, props,对应类成员类型
public class AccountServiceImpl implements IAccountService {
private String[] strArray;
private List<String> list;
private Set<String> set;
private Map<String, String> map;
private Properties prop;
public void setStrArray(String[] strArray) {
this.strArray = strArray;
}
public void setList(List list) {
this.list = list;
}
public void setSet(Set set) {
this.set = set;
}
public void setMap(Map map) {
this.map = map;
}
public void setProp(Properties prop) {
this.prop = prop;
}
}
<!-- 2、set方法注入
构造函数注入方式不能注入复杂/集合类型,需要使用set方法注入
数组形式:Array, List, Set
键值对形式:Map, Properties
-->
<bean id="accountService3" class="com.itheima.service.impl.AccountServiceImpl3">
<property name="strArray">
<!-- strArray = ["AAA", "BBB", "CCC"] -->
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<property name="list">
<list>
<value>l</value>
<value>i</value>
<value>s</value>
<value>t</value>
</list>
</property>
<property name="set">
<set>
<value>s</value>
<value>e</value>
<value>t</value>
</set>
</property>
<property name="map">
<!-- map = {"key1": value1, "key2": value2} -->
<map>
<entry key="key1" value="value1"></entry>
<entry key="key2">
<value>value2</value>
</entry>
</map>
</property>
<property name="prop">
<!-- prop = {"key1": properties} -->
<props>
<prop key="key1">properties</prop>
</props>
</property>
</bean>
1.2.3 通过注解实现依赖注入
1.2.3.1 对象注入通过注解实现,扫描配置通过bean.xml实现
用以下几个注解来告知spring那些java类需要创建bean对象
@Component:
作用:把当前类对象存入spring容器中
属性:
value:用于指定bean的id,默认为当前类名(首字母小写)
@Controller:一般用在表现层(作用与Component一样)
@Service:一般用在业务层(作用与Component一样)
@Repository:一般用在持久层(作用与Component一样)
另外需要配置bean.xml,需要注意两个部分:
- 需要修改命名空间
- 告知spring在创建IoC容器时要扫描的包
@Component("accountService")
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
public void saveAccount(){
accountDao.saveAccount();
}
}
<?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">
<!--告知spring在创建IoC容器时要扫描的包-->
<context:component-scan base-package="com.itheima"></context:component-scan>
</beans>
另外,当需要对类中的成员变脸注入数据时,可以Autowired,Qualifier,Resource和Value实现,其中,Autowired,Qualifier和Resource用于注入bean类型的数据,Value用于注入基本类型和Stirng类型的数据,集合类型的数据只能通过xml注入。
@Autowired
作用:自动按照类型注入
1)IoC容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
2)IoC容器中没有任何bean对象的类型和要注入的变量类型匹配,则报错
3)IoC容器中有多个bean对象类型和要注入的变量类型匹配,首先查看是否有变量名称与bean对象id一致的bean对象,如果有则注入,没有则报错
出现位置:可以是变量上,也可以是方法上
细节:在使用注解注入时,set方法就不是必须的了
@Qualifier
作用:在按照类中注入的基础之上,再按照名称注入
1)给类成员注入时需要和Autowired一起使用
2)给类方法参数注入时可单独使用???
属性:
value:用于指定bean的id
@Resource
作用:直接按照bean的id注入,可单独使用
属性:
name:指定bean对象的id
@Value
作用:用于注入基本类型和String类型的数据
属性:
value:用于指定数据的值,可以使用spring中SeEL(spring的EL表达式)
可通过注解Bean将当前方法的返回值作为bean对象存入spring容器中
@Bean
作用:把当前方法的返回值作为bean对象存入spring容器中
属性:
name:指定bean的id,默认为方法名
当使用Bean注解配置方法时,如果方法有参数,spring框架会从spring容器中查找有没有可用的bean对象, 查找方式和Autowired一样
@Bean(name = "runner") // createQueryRunner方法的返回值存入spring容器中,id为“runner”
@Scope("prototype") // 多例模式
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
1.2.3.2 完全通过注解实现依赖注入(不使用xml)
如果想完全通过注解的形式(不使用xml)来实现依赖注入,我们需要新建一个spring配置类,其作用与bean.xml一致,并使用以下两个注解。
@Configuration
作用:指定当前类为配置类
@ComponentScan
作用:指定spring容器创建时,要扫描的包
属性:
basePackage/value:指定要扫描的包
@Configuration // 指定当前类为配置类
@ComponentScan(basePackages = "com.itheima") // 指定spring容器创建时,要扫描的包
public class SpringConfiguration {
}
这里需要引入两个新的注解:Configuration和ComponentScan。这里Configuration的作用是指定当前类为配置类,即bean.xml的作用;另外,我们需要告知spring在创建IoC容器时要扫描的包,这就需要ComponentScan来实现,即实现了bean.xml中的配置:
<!--告知spring在创建IoC容器时要扫描的包,配置所需要的标签不是在beans的约束中,
而是以一个context的名称空间中 -->
<context:component-scan base-package="com.itheima"></context:component-scan>
另外,获取spring容器的方式也需要改变:
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
这样我们就完成了完全使用注解的形式来实现依赖注入。
同时,我们可以有多个配置类,比如SpringConfiguration类为主配置类,jdbcConfiguration类为其中一个关于jdbc的配置类,这个时候就可以通过Import注解实现。
@Import 作用:导入其他配置类,有Import注解的是主配置类,导入的是子配置类 属性: value:指定其他配置类的字节码
@Configuration
@ComponentScan(basePackages = "com.itheima")
@Import(value = jdbcConfiguration.class)
@PropertySource(value = "classpath:jdbcConfig.properties")
public class SpringConfiguration {
}