一、IOC的概念和Spring中基于XML的IOC (1)IOC概念 IOC:控制反转(把创建对象的权利交给框架) 原来: 我们在获取对象时,都是采用 new 的方式。是主动的。 现在:我们获取对象时,同时跟工厂要,有工厂为我们查找或者创建对象。是被动的。 这种被动接收的方式获取对象的思想就是控制反转,它是 spring 框架的核心之一 。
明确ioc 的作用:削减计算机程序的耦合(解除我们代码中的依赖关系)。
(2)使用Spring的IOC来解决程序的耦合 使用 spring 解决依赖关系,并不是真正的要做增删改查操作,所以此时我们没必要写实体类。
一、业务层的接口和实现类
public interface IAccountService { void saveAccount () ; } public class AccountServiceImpl implements IAccountService { private IAccountDao accountDao = new AccountDaoImpl(); @Override public void saveAccount () { accountDao.saveAccount(); } }
二、持久层接口和实现类
public interface IAccountDao { void saveAccount () ; } public class AccountDaoImpl implements IAccountDao { @Override public void saveAccount () { System.out.println("保存了账户" ); } }
1.基于xml开发的配置 (1)导包后在resources配置目录下创建bean.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" ></beans >
(2)让spring管理资源,在配置文件中配置 service 和 dao
<bean id ="accountService" class ="com.swpuembedded.service.impl.AccountServiceImpl" > </bean > <bean id ="accountDao" class ="com.swpuembedded.dao.impl.AccountDaoImpl" > </bean >
(3)模拟一个表现层(web)来测试配置是否成功
public class Client { public static void main (String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml" ); IAccountService aService = (IAccountService) ac.getBean("accountService" ); IAccountDao aDao = (IAccountDao) ac.getBean("accountDao" ); System.out.println(aService); System.out.println(aDao); } }
2.ApplicationContext ApplicationContext实际是就是spring中的一个工厂,通过工厂来获取bean对象。
(1)Spring的工厂类结构图
BeanFactory 才是 Spring 容器中的顶层接口。 ApplicationContext 是它的子接口。 核心容器的两个接口引发出的问题 * ApplicationContext: 单例对象 (智能) 更多采取此接口 * 它在构建核心容器时,创建对象采取的思想策略是采用立即加载的方式,也就是说只要一读取完配置文件就创建配置文件中配置的对象。 * BeanFactory: 多例对象 * 它在构建核心容器时,创建对象采取的思想策略是采用延迟加载的方式,也就是说什么时候根据id获取对象了,什么时候才真正的创建对象。
(2)ApplicationContext的三个常用的实现类 获取Spring的IOC核心容器,并根据ID获取对象
* (1)ClassPathXmlApplicationContext
* 可以加载类路径下的配置文件(配置文件在类的路径下,不在无法加载)
* (2)FileSystemXmlApplicationContext
* 可以加载磁盘任意路径,毕竟File,(必须有访问的权限)
* (3)AnnotationConfigApplicationContext
* 可以用于读取注解来创建容器,之后用的现在是xml配置
二、IOC中 bean标签 和 管理对象细节 (1)bean标签 在我们的bean.xml配置文件中,我们需要关注一些细节。
bean标签:用于配置对象让 spring 来创建的。默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。
id:给对象在容器中提供一个唯一标识。用于获取对象。 class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。 scope:指定对象的作用范围。 * singleton :默认值,单例的. * prototype :多例的.
<bean id ="accountService" class ="com.swpuembedded.service.impl.AccountServiceImpl" > </bean > <bean id ="accountDao" class ="com.swpuembedded.dao.impl.AccountDaoImpl" > </bean >
(2)Spring对bean的管理细节 1.创建bean的三种方式 第一种方式:使用默认构造函数创建 在spring的配置文件中使用bean标签,配以id和class且没有其他属性和标签时 ,采用的就是默认构造函数bean对象,此时如果类中没有默认构造函数,则实例化对象(AccountServiceImpl)无法创建
<bean id ="accountService" class ="com.swpuembedded.service.impl.AccountServiceImpl" > </bean >
public class AccountServiceImpl implements IAccountService { public AccountServiceImpl () { System.out.println("AccountServiceImpl对象创建了" ); } public void saveAccount () { System.out.println("service中的saveAccount方法执行了" ); } }
第二种方式:使用普通工厂中的方法创建对象(使用某个类中的方法创建对象并存入spring容器)
该类存在jar包,InstanceFactory只是模拟而已 <bean id ="instanceFactory" class ="com.swpuembedded.factory.InstanceFactory" > </bean > <bean id ="accountService" factory-bean ="instanceFactory" factory-method ="getAccountService" > </bean >
public class InstanceFactory { public IAccountService getAccountService () { return new AccountServiceImpl(); } }
第三种方式:使用静态工厂中的静态方法创建对象 (使用某个类中的静态方法创建对象,并存入spring容器)
<bean id ="accountService" class ="com.swpuembedded.factory.StaticFactory" factory-method ="getAccountService" > </bean >
与第二种方法的区别只是方法成为了静态方法,便可在class 后加factory -method /** 3. @author Mango 4. 使用静态工厂中的静态方法创建对象 */ public class StaticFactory { public static IAccountService getAccountService () { return new AccountServiceImpl(); } }
2.bean对象的作用范围 bean标签中的scope属性 (1)作用:用于指定bean的作用范围
一个应用只有一个对象的实例。或者是,每次访问对象时,都会重新创建对象实例。
(2)取值:常用的就是单例和多例的 singleton:单例的(默认值) prototype:多例的 request:作用于web应用的请求范围 session:作用于web应用的会话范围 global-session:作用于集群环境的会话范围(全局会话范围) ,当不是集群环境时,它就是session
3.bean对象的生命周期 (1)单例对象 创建:当容器创建时,对象变创建 存在:只要容器存在,对象一直存在 销毁:只要容器销毁,便销毁了注:单例对象与容器的生命周期相同
(2)多例对象创建:当我们使用对象时,spring框架才为我们创建 存在:对象只要是在使用过程中就一直存在销毁:当对象长时间的不使用时,且没有别的对象引用时,由Java的垃圾回收器回收
三、依赖注入(Dependency Injection) 概念:在当前类需要用到其他类的对象 ,由spring为我们提供,我们只需要在配置文件中说明依赖关系的维护,就成为依赖注入
(1)注入数据类型 依赖注入(使用bean标签):能注入的数据,有三类 (1)基本类型 和String (2)其他的bean类型(在配置文件中或者注解配置过得bean )
<bean id ="accountService2" class ="com.swpuembedded.service.impl.AccountServiceImpl2" > <property name ="name" value ="泰斯特" > </property > <property name ="age" value ="18" > </property > <property name ="birthday" ref ="now" > </property > </bean > <bean id ="now" class ="java.util.Date" > </bean >
(3)复杂类型/集合类型
(2)注入方式 注入的方式,有三种:
第一种:使用构造函数来提供
顾名思义,就是使用类中的构造函数,给成员变量赋值 。注意,赋值的操作不是我们自己做的,而是通过配置的方式,让 spring 框架来为我们注入。
使用的标签是:constructor-arg 标签出现的位置是:bean标签的内部 标签中的属性 type:用于指定要注入的数据的数据类型,数据类型也是构造函数中的某个或者某些参数的类型 index:用于指定要注入的数据构造函数中指定索引位置的参数赋值,索引的位置为0开始 name:用于指定给构造函数中指定名称的参数赋值 (常用的)
//用于指定给构造函数中哪个参数赋值
value:用于给基本类型(string)的数据
ref:用于指定其他的bean类型,它指的就是在spring的IOC核心容器中出现过的bean对象
优势:在获取bean对象时,注入数据时必须的操作,否则对象无法创建成功
弊端:改变了bean对象的实例化方式,使我们在创建对象时如果用不到也必须提供。
<bean id ="accountService" class ="com.swpuembedded.service.impl.AccountServiceImpl" > <constructor-arg name ="name" value ="test" > </constructor-arg > <constructor-arg name ="age" value ="18" > </constructor-arg > <constructor-arg name ="birthday" ref ="now" > </constructor-arg > </bean >
第二种:使用set方法提供
涉及的标签:property 出现的位置:bean标签的内部
标签的属性:
name:name:用于指定注入时所调用的set方法名称,不管类中的属性名称
value:用于给基本类型(string)的数据
ref:用于指定其他的bean类型,它指的就是在spring的IOC核心容器中出现过的bean对象
优势:创建对象时没有明确的限制。可以直接使用默认构造函数
弊端:如果某个成员必须有值,则获取对象时有可能set方法没有执行
<bean id ="accountService2" class ="com.swpuembedded.service.impl.AccountServiceImpl2" > <property name ="name" value ="泰斯特" > </property > <property name ="age" value ="18" > </property > <property name ="birthday" ref ="now" > </property > </bean >
第三种:使用注解来提供(之后具体写)
(3)注入集合属性—多个值 顾名思义就是给类中的集合成员传值。
它用的也是set方法注入的方式,只不过变量的数据类型都是集合 。我们这里介绍注入数组List,Set,Map,Properties。
在需要引入依赖的类中:
public class AccountServiceImpl implements IAccountService { private String[] myStrs; private List<String> myList; private Set<String> mySet; private Map<String,String> myMap; private Properties myProps; public void setMyStrs (String[] myStrs) { this .myStrs = myStrs; } public void setMyList (List<String> myList) { this .myList = myList; } public void setMySet (Set<String> mySet) { this .mySet = mySet; } public void setMyMap (Map<String, String> myMap) { this .myMap = myMap; } public void setMyProps (Properties myProps) { this .myProps = myProps; } @Override public void saveAccount () { System.out.println(Arrays.toString(myStrs)); System.out.println(myList); System.out.println(mySet); System.out.println(myMap); System.out.println(myProps); } }
<bean id ="accountService3" class ="com.swpuembedded.service.impl.AccountServiceImp3" > <property name ="myStrs" > <array > <value > AAA</value > <value > BBB</value > </array > </property > <property name ="myList" > <list > <value > AAA</value > <value > BBB</value > </list > </property > <property name ="mySet" > <set > <value > AAA</value > <value > BBB</value > </set > </property > <property name ="myMap" > <map > <entry key ="testA" value ="AAA" > </entry > <entry key ="testB" value ="BBB" > </entry > </map > </property > <property name ="myProperties" > <props > <prop key ="testC" > CCC</prop > <prop key ="testD" > DDD</prop > </props > </property > </bean >