IOC[inversion Of Control 反转控制]
在传统的开发模式下,需要使用JdbcUtils / 反射,由程序员编写程序, 在程序中读取配置信息 ,然后创建对象, new Object???() // 反射方式,再使用对象完成任务。程序员不能够专注的实现对象对业务的处理。
IOC的开发模式很好的解决了这个问题。Spring 根据配置文件 xml/注解 创建对象,并将对象放入到容器(ConcurrentHashMap)中, 可以完成对象之间的依赖。
当需要使用某个对象实例的时候, 可以直接从容器中获取。程序员就可以更加关注如何使用对象完成相应的业务, (以前需要 new … ==> 注解/配置 方式)。
DI(Dependency Injection)依赖注入,可以理解成是 IOC 的另外叫法。Spring 最大的价值是通过配置,给程序提供需要使用的web 层[Servlet(Action/Controller)]/Service/Dao/[JavaBean/entity]对象, 这个是核心价值所在,也是 ioc 的具体体现,实现解耦。
Spring 快速入门实例
在开始之前我们需要下载spring5的开发包。
commons-logging-1.1.3.jar:spring日志需要的jar。
spring开发ioc基本包:
spring-beans-5.3.8.jar
spring-context-5.3.8.jar
spring-core-5.3.8.jar
spring-expression-5.3.8.jar
还要导入Dom4j.jar包
创建一个beans.xml存放bean。
<!--配置Monster对象--> <bean id="monster" class="com.spring.bean.Monster"> <property name="monsterId" value="1"/> <property name="name" value="蜈蚣精"/> <property name="skill" value="蜇人"/> </bean>
获取对象并给对象属性赋值输出。
package com.spring.test; import com.spring.beans.Monster; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import java.io.File; import java.util.List; import java.util.concurrent.ConcurrentHashMap; public class ApplicationContext { private ConcurrentHashMap<String, Object> ioc = new ConcurrentHashMap<>(); public ApplicationContext(String iocBeanXmlFile) throws DocumentException, ClassNotFoundException, IllegalAccessException, InstantiationException { //反射的方式得到->使用dom4j //得到一个解析器 SAXReader reader = new SAXReader(); Document document = reader.read(new File(iocBeanXmlFile)); //1. 得到rootElement Element rootElement = document.getRootElement(); //2. 获取第1 个bean, 如果有多个就遍历所有 Element bean = (Element) rootElement.elements("bean").get(0); String id = bean.attributeValue("id"); String classFullPath = bean.attributeValue("class"); List<Element> property = bean.elements("property"); Integer monsterId = Integer.parseInt(property.get(0).attributeValue("value")); String name = property.get(1).attributeValue("value"); String skill = property.get(2).attributeValue("value"); //3. 使用反射创建bean 实例,并放入到ioc 中 Class cls = Class.forName(classFullPath); Monster instance = (Monster)cls.newInstance(); instance.setMonsterId(monsterId); instance.setName(name); instance.setSkill(skill); ioc.put(id, instance); } public Object getBean(String id) { return ioc.get(id); } }
创建一个测试类
package com.spring.test; import com.spring.beans.Monster; import org.dom4j.DocumentException; public class SpringIOCTest { public static void main(String[] args) throws DocumentException, IllegalAccessException, InstantiationException, ClassNotFoundException { //得到beans.xml 文件. ApplicationContext ioc = new ApplicationContext("src/beans.xml"); Monster monster01 = (Monster)ioc.getBean("monster01"); System.out.println("ioc 的monster01= " + monster01); } }
获取bean的方法
通过类型获取bean
//通过类型来获取容器的bean 对象 @Test public void getMonsterByType() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); //创建容器 Monster monster = ioc.getBean(Monster.class); //获取容器中Monster类型的bean对象 System.out.println("monster=" + monster); Monster monster1 = ioc.getBean(Monster.class); System.out.println("monster == monster1 的值= " + (monster == monster1)); }
按类型来获取bean, 要求ioc 容器中的同一个类的bean 只能有一个, 否则会抛出异常NoUniqueBeanDefinitionException。一般应用于在一个线程中只需要一个对象实例(单例)的情况。在容器配置文件(比如beans.xml)中给属性赋值, 底层是通过setter 方法完成的。
通过构造器配置bean
在spring的ioc容器,可以通过构造器来配置bean对象。
<bean id="monster02" class="com.spring.beans.Monster"> <constructor-arg value="2" index="0"/> <constructor-arg value="蜘蛛精" index="1"/> <constructor-arg value="蛛丝束缚" index="2"/> //1. 通过index 属性来区分是第几个参数 </bean> <!--数据类型就是对应的Java 数据类型,按构造器参数顺序--> <bean id="monster03" class="com.spring.beans.Monster"> <constructor-arg value="3" type="java.lang.Integer"/> <constructor-arg value="白骨精" type="java.lang.String"/> <constructor-arg value="白骨鞭" type="java.lang.String"/> </bean> //2. 通过type 属性来区分是什么类型(按照顺序)
通过p名称空间配置bean
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--在spring 的ioc 容器, 可以通过p 名称空间来配置bean 对象--> <bean id="monster04" class="com.spring.beans.Monster" p:monsterId="4" p:name="红孩儿" p:skill="吐火~" />
引用/注入其它bean 对象
在spring 的ioc 容器, 可以通过ref 来实现bean 对象的相互引用。
<!-- bean 对象的相互引用 1. 其它含义和前面一样 2. ref 表示memberDAO 这个属性将引用/指向id = memberDAOImpl 对象 --> <bean id="memberServiceImpl" class="com.spring.service.MemberServiceImpl"> <property name="memberDAO" ref="memberDAOImpl"/> </bean> <bean id="memberDAOImpl" class="com.spring.dao.MemberDAOImpl"/>
引用/注入内部bean 对象
<bean id="memberServiceImpl02" class="com.spring.service.MemberServiceImpl"> <property name="memberDAO"> <bean class="com.spring.dao.MemberDAOImpl"/> </property> </bean>
引用/注入集合/数组类型
<bean id="master01" class="com.spring.beans.Master"> <property name="name" value="太上老君"/> <!-- 给bean 对象的list 集合赋值--> <property name="monsterList"> <list> <ref bean="monster03"/> <ref bean="monster02"/> </list> </property> <!-- 给bean 对象的map 集合赋值--> <property name="monsterMap"> <map> <entry> <key> <value>monsterKey01</value> </key> <ref bean="monster01"/> </entry> <entry> <key> <value>monsterKey02</value> </key> <ref bean="monster02"/> </entry> </map> </property> <!-- 给bean 对象的properties 集合赋值--> <property name="pros"> <props> <prop key="k1">Java 工程师</prop> <prop key="k2">前端工程师</prop> <prop key="k3">大数据工程师</prop> </props> </property> <!-- 给bean 对象的数组属性注入值--> <property name="monsterName"> <array> <value>银角大王</value> <value>金角大王</value> </array> </property> <!-- 给bean 对象的set 属性注入值--> <property name="monsterSet"> <set> <ref bean="monster01"/> <bean class="com.spring.beans.Monster"> <property name="monsterId" value="10"/> <property name="name" value="玉兔"/> <property name="skill" value="钻地洞"/> </bean> </set> </property> </bean>
测试
@Test public void setCollectionByPro() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); Master master01 = ioc.getBean("master01", Master.class); //获取list 集合 System.out.println("======list======="); List<Monster> monster_list = master01.getMonsterList(); for (Monster monster : monster_list) { System.out.println(monster); } //获取map 集合 System.out.println("======map======="); Map<String, Monster> monster_map = master01.getMonsterMap(); Set<Map.Entry<String, Monster>> entrySet = monster_map.entrySet(); for (Map.Entry<String, Monster> entry : entrySet) { System.out.println(entry); } //获取properties 集合 System.out.println("======properties======="); Properties pros = master01.getPros(); String property1 = pros.getProperty("k1"); String property2 = pros.getProperty("k2"); String property3 = pros.getProperty("k3"); System.out.println(property1 + "\t" + property2 + "\t" + property3); //获取数组 System.out.println("======数组======="); String[] monsterName = master01.getMonsterName(); for (String s : monsterName) { System.out.println("妖怪名= " + s); } //获取set System.out.println("======set======="); Set<Monster> monsterSet = master01.getMonsterSet(); for (Monster monster : monsterSet) { System.out.println(monster); } }
细节
- 1.主要掌握List/Map/Properties 三种集合的使用。
- 2.Properties 集合的特点。
- 1.这个Properties 是Hashtable 的子类, 是key-value 的形式。
- 2.key 是string 而value 也是string。
通过util 名称空间创建list
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!--通过util 名称空间来创建list 集合,可以当做创建bean 对象的工具来使用--> <util:list id="myListBook"> <value>三国演义</value> <value>西游记</value> <value>红楼梦</value> <value>水浒传</value> </util:list> <bean id="bookStore" class="com.spring.beans.BookStore"> <property name="bookList" ref="myListBook"/> </bean>
级联属性赋值
spring 的ioc 容器, 可以直接给对象属性的属性赋值, 即级联属性赋值。
<bean id="emp" class="com.spring.beans.Emp"> <property name="name" value="jack"/> <property name="dept" ref="dept"/> <property name="dept.name" value="Java 开发部"/> </bean> <bean id="dept" class="com.spring.beans.Dept"/>
package com.spring.beans; public class Dept { private String name; public Dept() { } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package com.spring.beans; public class Emp { private String name; private Dept dept; public Emp() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public Dept getDept() { return dept; } public void setDept(Dept dept) { this.dept = dept; } }