6.对象依赖注入
本节,我们来学习如何在spring IoC容器中设置对象的依赖关系。这个过程我们称为依赖注入。依赖注入说白了就是将两个对象关联起来。
依赖注入是指运行时将容器内对象利用反射赋值给其他对象的操作。
利用setter实现静态数值注入
这个bean,里面包含的属性一律采用property这个标签来指代。property标签最基础的有2个属性,第一个是name,指属性名,第二个是value,指属性值。在创建好这个bean以后,便会通过反射机制调用各属性的setter方法来动态设置数值。
基于构造方法注入对象
注入集合对象
前面写的注入对象都是单个对象,这一节我要讲解List或Set等这样的集合对象注入。注意各标签的大小写。
可以用value标签来设置具体的数值,或者ref引入具体的bean。
list和set的区别是list里面的元素不允许出现重复,而set里面的元素可以出现重复。
properties只允许key和value是字符串类型的。
下面是一个样例:
<bean id="company" class="com.haiexijun.ioc.entity.Company"> <property name="rooms"> <list> <value>201-总裁办</value> <value>202-总经理办公室</value> <value>203-研发部会议室</value> <value>203-研发部会议室</value> </list> </property> <property name="computers"> <map> <entry key="dev-112" value-ref="computer1"></entry> <entry key="dev-113"> <bean class="com.haiexijun.ioc.entity.Computer"> <constructor-arg name="brand" value="联想"/> <constructor-arg name="price" value="2222"/> <constructor-arg name="sn" value="12312412"/> <constructor-arg name="type" value="台式机"/> </bean> </entry> </map> </property> <property name="info"> <props> <prop key="phone">13214124</prop> <prop key="address">zjian</prop> </props> </property> </bean> <bean id="computer1" class="com.haiexijun.ioc.entity.Computer"> <constructor-arg name="brand" value="联想"/> <constructor-arg name="price" value="2222"/> <constructor-arg name="sn" value="12312412"/> <constructor-arg name="type" value="台式机"/> </bean>
这里就不作过多的解释了。
查看容器内对象
前面学习了如何在容器内创建对象,以及设计对象的关系。但是所有这些信息都是通过脑补来完成的。如果一个工程越来越大,
对象越来越多,那我们如何知道当前容器中到底有多少对象,这些对象又是什么类型呢?
可以通过ApplicationContext对象的getBeanDefinitionNames()方法获取到bean的名字的String数组。通过类对象.getClass().getName()来获取全类名,如context.getBean(beanName).getClass().getName()。如果要获取实体类具体的内容,用实体类对象.toString() 方法。
7.Bean对象的作用域及生命周期
bean scope属性详解
scope的原意是范围的意思。
bean scope属性用于决定对象何时被创建与作用的范围。通过设置 scope属性会影响到容器内对象的数量。默认情况下bean会在IoC容器创建后自动实例化,全局唯一。
下面是singleton单例示意图
单例的执行效率高,不用多次创建同一个对象,但也会引发很多线程安全问题。
下面是prototype多例示意图:
singleton 与 prototype对比:
IoC的生命周期
下面写一个案例来演示IoC的生命周期:
配置好了项目后,创建一个entity实体类,名为Order:
package com.haiexijun.ioc.entity; public class Order { private Float price; private Integer quantity; private Float total; public Order(){ System.out.println("创建Order对象"+this); } public void init(){ System.out.println("执行Init方法"); total=price*quantity; } public void destroy(){ System.out.println("销毁容器,释放Order对象相关的资源"); } public void pay(){ System.out.println("订单金额为:"+total); } public Float getPrice() { return price; } public void setPrice(Float price) { System.out.println("设置price:"+price); this.price = price; } public Integer getQuantity() { return quantity; } public void setQuantity(Integer quantity) { System.out.println("设置quantity:"+quantity); this.quantity = quantity; } public Float getTotal() { return total; } public void setTotal(Float total) { this.total = total; } }
然后在applicationContext.xml文件中编写bean
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="order1" class="com.haiexijun.ioc.entity.Order" init-method="init" destroy-method="destroy"> <property name="price" value="19.8"/> <property name="quantity" value="1000"/> </bean> </beans>
会发现,我并没有在bean中为total属性设置属性和属性值,而是通过init-method属性指定order类里面的init方法来计算total来设置total属性的。我们还定义了一个destroy-method的属性,用于指定IoC容器被销毁后执行的方法,一般用于释放与该对象关联的资源。
最后编写代码运行:
package com.haiexijun.ioc; import com.haiexijun.ioc.entity.Order; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringApplication { public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); System.out.println("====IoC容器以初始化完成===="); Order order= context.getBean("order1", Order.class); order.pay(); //销毁容器,会自动调用xml中设置的destroy-method方法 ((ClassPathXmlApplicationContext)context).registerShutdownHook(); } }
运行结果如下: