IOC是什么?
ioc(Inversion of Control),即“控制反转”,它不是什么技术,而是一种设计思想;指的是在开发中,将对象交给容器去创建,而不是在对象内部直接创建
为什么叫“控制反转”
传统的应用程序是由我们去在对象中 主动 创建依赖对象,这叫“正转”;而IOC则是将依赖对象由容器去创建,容器帮我们查找及注入依赖对象,注入什么对象就接受什么,只能 被动 接受;这和传统的主动指定正好相反,所以称 为控制反转
1.SpringIOC的xml配置
1.1.对象的注入
1.1.1.创建maven项目
1.1.2.在pom.xml文件中加入依赖配置
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId> org.springframework </groupId>
<artifactId> spring-context </artifactId>
<version> 4.3.3.RELEASE </version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
1.1.3.编写Dao接口和实现
接口:
/**
* 模拟数据库处理
* @author MY
*
*/
public interface CustomerDao {
void save();
}
实现类:
import com.test.spring.ioc.dao.CustomerDao;
public class CustomerDaoImpl implements CustomerDao{
public void init(){
System.out.println("CustomerDaoImpl对象的初始化方法");
}
public void destroy(){
System.out.println("CustomerDaoImpl对象的销毁方法");
}
public void save() {
System.out.println("保存到mysql数据库中!");
}
}
1.1.4.编写service接口和实现类
接口:
public interface CustomerService {
void save();
}
实现类:
import com.test.spring.ioc.dao.CustomerDao;
import com.test.spring.ioc.service.CustomerService;
public class CustomerServiceImpl implements CustomerService{
private String name;
private CustomerDao customerDao;
//1.构造方法注入
public CustomerServiceImpl(CustomerDao customerDao){
this.customerDao = customerDao;
}
//无参构造器(使用setter方法注入时,必须有无参构造器)
public CustomerServiceImpl(){
super();
}
//2.setter方法注入
public void setCustomerDao(CustomerDao customerDao) {
this.customerDao = customerDao;
}
public void setName(String name) {
this.name = name;
}
public void save() {
customerDao.save();
System.out.println(name);
}
}
1.1.5.编写applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 使用p名称空间注入 需要加xmlns:p="http://www.springframework.org/schema/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">
<!-- scope的值有
singleton 创建一个单例的对象
prototype 每次都重新创建一个对象
request 用在web项目中,保证一个请求创建一个对象
session 用在web项目中,保证一个会话创建一个对象
默认情况下是 单例 singleton
-->
<bean id="customerDao" class="com.test.spring.ioc.dao.impl.CustomerDaoImpl" scope="prototype" />
<!--
* 销毁和初始化的方法调用配置
* 测试 为对象指定初始化方法 init-method
* 销毁方法 destroy-method
* 注意:最好在单例中使用,否则销毁方法不起作用
* 配置的方法,在对应的bean中
-->
<!-- <bean id="customerDao" class="com.test.spring.ioc.dao.impl.CustomerDaoImpl"
init-method="init" destroy-method="destroy"/> -->
<!-- <bean id="customerService" class="com.test.spring.ioc.service.impl.CustomerServiceImpl">
1.构造器注入
index 参数的索引 从0开始
<constructor-arg index="0" ref="customerDao" />
2.setter方式注入
注意:使用setter方式注入,该类必须有无参构造方法
name:类的属性名
ref:对应的bean的id
<property name="customerDao" ref="customerDao" />
</bean> -->
<!-- 3.使用p名称空间注入
注意:p名称空间注入其实是简化的setter方式注入,所以,一定要有set方法
p:属性 : 注入普通的数据(例如 String)
p:属性-ref: 注入 JavaBean 对象(例如 CustomerDao)
-->
<!-- <bean id="customerService" class="com.test.spring.ioc.service.impl.CustomerServiceImpl" p:customerDao-ref="customerDao"
p:name="test" /> -->
<bean id="user" class="com.test.spring.ioc.UserModel">
<property name="name" value="夏天" />
<property name="age" value="12" />
</bean>
<!-- 4.spEL 表达式注入(可以使用在 setter 方法和构造方法上面的)
注意:spEL 表达式,springEL 表达式,是 spring3.0 以后的新特性。
1. #{对象bean的id}——注入对象。
2. #{对象bean的id.属性名}——将对象的属性注入。
3. #{'值'}——直接注入该值
-->
<bean id="customerService" class="com.test.spring.ioc.service.impl.CustomerServiceImpl">
<!-- <constructor-arg index="0" value="#{customerDao}" /> -->
<property name="customerDao" value="#{customerDao}" />
<!-- <property name="name" value="#{'test'}" /> -->
<property name="name" value="#{user.name}" />
</bean>
</beans>
1.1.6.测试代码
public class SpringIOCTest {
//读取配置文件,初始化ioc容器
ApplicationContext ac = null;
@Before
public void init(){
ac = new ClassPathXmlApplicationContext("spring_ioc/applicationContext.xml");
}
/**
* spring的IOC入门程序
*/
@Test
@Ignore
public void test1(){
//从ioc容器中根据id的值获取对应的对象
CustomerDao bean = (CustomerDao) ac.getBean("customerDao");
bean.save();
System.out.println(bean);
}
/**
* 测试scope
* scope的值有
* singleton 创建一个单例的对象
* prototype 每次都重新创建一个对象
* request 用在web项目中,保证一个请求创建一个对象
* session 用在web项目中,保证一个会话创建一个对象
* 默认情况下是 单例 singleton
*/
@Test
@Ignore
public void test2(){
//从ioc容器中根据id的值获取对应的对象
for(int i=0;i<5;i++){
CustomerDao bean = (CustomerDao) ac.getBean("customerDao");
System.out.println(bean);
}
}
/**
* 销毁和初始化的方法调用配置
* 测试 为对象指定初始化方法 init-method
* 销毁方法 destroy-method
* 注意:最好在单例中使用,否则销毁方法不起作用
* 配置的方法,在对应的bean中
*/
@Test
@Ignore
public void test3(){
CustomerDao bean = (CustomerDao) ac.getBean("customerDao");
System.out.println(bean);
//手动销毁
((AbstractApplicationContext)ac).registerShutdownHook();
}
/**
* 测试注入方法
*/
@Test
public void test4(){
CustomerService bean = (CustomerService) ac.getBean("customerService");
bean.save();
}
}
xml配置总结:
1.ApplicationContext是Spring容器最常用的接口,该接口有如下两个实现类:
ClassPathXmlApplicationContext: 从类加载路径下搜索配置文件,并根据配置文件来创建Spring容器(推荐)
FileSystemXmlApplicationContext:从文件系统的相对路径或绝对路径下去搜索配置文件,并根据配置文件来创建Spring容器(需要写文件的全路径,该路径多变)
2.单例多例问题(如果bean中不设置,默认为单例)
scope 配置
包括:
singleton: 创建一个单例的对象
prototype: 每次创建一个对象(多例的)
request: 用在 web 项目中,保证一个请求创建一个对象
session: 用在 web 项目中,保证一个会话创建一个对象
3.给对象设置初始化方法和销毁方法(注意:该对象必须为单例的)
在bean中增加配置:
init-method: 初始化方法( init-method=”init”)
destroy-method: 销毁方法( destroy-method=”init”)
4.依赖注入的方式
构造方式参数注入
setter 方法注入
名称空间注入
注意:需在 applicationContext.xml 引入 p 名称空间
p 名称空间是简化的 setter 方法注入,所以必须要有 setter 方法
p:属性 : 注入普通的数据(例如 String)
p:属性-ref: 注入 JavaBean 对象(例如 CustomerDao)
spEL 表达式注入
注意:spEL 表达式,springEL 表达式,是 spring3.0 以后的新特性
1.2不同类型的注入
1.2.1.编写一个user对象和一个user对象的包装类
user类
public class User {
private String name;
private String gender;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "User [name=" + name + ", gender=" + gender + "]";
}
}
user的包装类
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
public class DecorateUser {
//1基本类型
private String baseStr;
//2.对象类型
private User user;
//3.数组类型
private String[] arrs;
//4.List类型
private List<User> users;
//5.Map类型
private Map<String,User> maps;
private Map<String,String> map;
//6.properties类型
private Properties pro;
public String getBaseStr() {
return baseStr;
}
public void setBaseStr(String baseStr) {
this.baseStr = baseStr;
}
public User getUser() {
return user;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setUser(User user) {
this.user = user;
}
public String[] getArrs() {
return arrs;
}
public void setArrs(String[] arrs) {
this.arrs = arrs;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public Map<String, User> getMaps() {
return maps;
}
public void setMaps(Map<String, User> maps) {
this.maps = maps;
}
public Properties getPro() {
return pro;
}
public void setPro(Properties pro) {
this.pro = pro;
}
@Override
public String toString() {
return "DecorateUser [baseStr=" + baseStr + ", user=" + user + ", arrs=" + Arrays.toString(arrs) + ", users="
+ users + ", maps=" + maps + ", map=" + map + ", pro=" + pro + "]";
}
}
1.2.2.编写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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="u1" class="com.test.spring.ioc.baseType.User">
<property name="name" value="张1" />
<property name="gender" value="男" />
</bean>
<bean id="u2" class="com.test.spring.ioc.baseType.User">
<property name="name" value="张2" />
<property name="gender" value="男" />
</bean>
<bean id="u3" class="com.test.spring.ioc.baseType.User">
<property name="name" value="张3" />
<property name="gender" value="男" />
</bean>
<bean id="decorateUser" class="com.test.spring.ioc.baseType.DecorateUser">
<!-- 基础类型注入 -->
<property name="baseStr" value="测试" />
<!-- 对象类型注入 -->
<property name="user" ref="u1" />
<!-- 数组类型注入 -->
<property name="arrs">
<array>
<value>111111</value>
<value>222222</value>
</array>
</property>
<!-- list注入 -->
<property name="users">
<list>
<ref bean="u1"/>
<ref bean="u2"/>
<ref bean="u3"/>
</list>
</property>
<!-- Map注入
注意:带-ref的表示引入对象
-->
<property name="maps">
<map>
<entry key="001" value-ref="u1" />
<entry key="002" value-ref="u2" />
<entry key="003" value-ref="u3" />
</map>
</property>
<property name="map">
<map>
<entry key="001" value="测试1" />
<entry key="002" value="测试2" />
<entry key="003" value="测试3" />
</map>
</property>
<!-- properties类型注入 -->
<property name="pro">
<props>
<prop key="pro1">测试1</prop>
<prop key="pro2">测试2</prop>
</props>
</property>
</bean>
</beans>
1.2.3.测试代码
/**
* spring基本类型注入测试
* @author MY
*
*/
public class BaseTypeTest {
@Test
public void test1(){
ApplicationContext ac = new ClassPathXmlApplicationContext("spring_ioc/applicationContextBaseType.xml");
DecorateUser user = (DecorateUser) ac.getBean("decorateUser");
System.out.println(user.toString());
}
}