IOC控制反转的原理
ioc快速入门案例
1、创建文件
2、Monster
public class Monster {
private Integer id;
private String nickName;
private String skill;
public Monster() {
System.out.println("monster创建。。。");
}
public Monster(Integer id, String nickName, String skill) {
this.id = id;
this.nickName = nickName;
this.skill = skill;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
@Override
public String toString() {
return "Monster{" +
"id=" + id +
", nickName='" + nickName + '\'' +
", skill='" + skill + '\'' +
'}';
}
}
3、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">
<!--配置一个Monster bean-->
<bean id="monstr01" class="com.spring.bean.Monster">
<property name="id" value="100"/>
<property name="nickName" value="牛魔王"/>
<property name="skill" value="芭蕉扇"/>
</bean>
</beans>
4、调用
public class IocTest {
private ClassPathXmlApplicationContext applicationContext;
/**
* 加载spring容器
*/
public void init () {
applicationContext =
new ClassPathXmlApplicationContext("beans.xml");
}
/**
* 从bean.xml中获取bean
*/
@Test
public void test() {
Object bean = applicationContext.getBean("monstr01");
System.out.println("bean"+bean);
}
}
spring中bean的获取方法
1、按beans.xml中的id获取(快速入门案例)
2、按类型获取// Monster.class
/**
* 从bean.xml中获取bean
* 1.通过类型来获取bean对象,前提是beans.xml中只有一个这个类型的bean对象
*/
@Test
public void test() {
Object bean = applicationContext.getBean(Monster.class);
System.out.println("bean"+bean);
}
spring配置bean
一、通过构造器(两种方式)来配置bean属性
1、方式一 <constructor-arg index="0" value="200"/>
2、方式二 <constructor-arg type="java.lang.Integer" value="300"/>
<!-- 通过构造器来配置bean对象
方式1、使用index参数来指定位置
-->
<bean id="monstr02" class="com.spring.bean.Monster">
<constructor-arg index="0" value="200"/>
<constructor-arg index="1" value="白骨精"/>
<constructor-arg index="2" value="吃人"/>
</bean>
<!-- 通过构造器来配置bean对象
方式2、使用type参数
-->
<bean id="monstr03" class="com.spring.bean.Monster">
<constructor-arg type="java.lang.Integer" value="300"/>
<constructor-arg type="java.lang.String" value="红孩儿"/>
<constructor-arg type="java.lang.String" value="三位真火"/>
</bean>
二、通过P命名空间配置bean
注意在xml文件头配置 p 标签 xmlns:p="http://www.springframework.org/schema/p"
<!--通过P命名空间来配置bean对象-->
<bean id="monstr04" class="com.spring.bean.Monster"
p:id="400" p:nickName="蜘蛛精" p:skill="吐口水"
/>
三、bean对象引用其他bean
ref
<!--bean对象引用其他bean-->
<bean id="master01" class="com.spring.bean.Master">
<property name="monster" ref="monstr01"/>
<property name="name" value="太上老君"/>
</bean>
package com.spring.bean;
public class Master {
private String name;
private Monster monster;
四、配置内部bean对象
<!--配置内部bean对象-->
<bean id="master02" class="com.spring.bean.Master">
<property name="name" value="地藏王"/>
<property name="monster" ref="monstr02"/>
<property name="monster2">
<bean class="com.spring.bean.Monster">
<property name="id" value="500"/>
<property name="skill" value="谛听"/>
<property name="nickName" value="顺风耳"/>
</bean>
</property>
</bean>
五、 给有List集合属性的bean赋值
public class Master {
private String name;
private Monster monster;
private Monster monster2;
private List<Monster> monsterList;
<!--给list集合属性的bean赋值-->
<bean id="master02" class="com.spring.bean.Master">
<property name="name" value="地藏王"/>
<property name="monster" ref="monstr02"/>
<property name="monster2" ref="monstr01"/>
<property name="monsterList">
<list>
<ref bean="monstr03"/>
<ref bean="monstr04"/>
</list>
</property>
@Test
public void test03() {
Master master = (Master)applicationContext.getBean("master03");
List<Monster> monsterList= master.getMonsterList();
System.out.println("master:"+master);
for (Monster monster: monsterList){
System.out.println("monster:"+monster);
}
}
六、给有Map集合属性的bean赋值
public class Master {
private String name;
private Monster monster;
private Monster monster2;
private Map<String,Monster> monsterMap;
<!--给Map集合属性的bean赋值-->
<bean id="master04" class="com.spring.bean.Master">
<property name="name" value="地藏王"/>
<property name="monster" ref="monstr02"/>
<property name="monster2" ref="monstr01"/>
<property name="monsterMap">
<map>
<entry>
<key>
<value>monsterMap01</value>
</key>
<ref bean="monstr03"/>
</entry>
<entry >
<key>
<value>monsterMap02</value>
</key>
<ref bean="monstr04"/>
</entry>
</map>
</property>
</bean>
@Test
public void test03() {
Master master = (Master)applicationContext.getBean("master04");
Map<String, Monster> monsterMap = master.getMonsterMap();
System.out.println(monsterMap);
for (Map.Entry<String,Monster> entry : monsterMap.entrySet()){
System.out.println("entrykey:"+entry.getKey()+"entryValue:"+entry.getValue());
}
}
七、给有Property属性的bean赋值
public class Master {
private String name;
private Monster monster;
private Monster monster2;
private Map<String,Monster> monsterMap;
private Properties ps;
<!--给Properties集合属性的bean赋值-->
<bean id="master05" class="com.spring.bean.Master">
<property name="name" value="地藏王"/>
<property name="monster" ref="monstr02"/>
<property name="monster2" ref="monstr01"/>
<property name="ps">
<props>
<prop key="prokey01">牛魔王</prop>
<prop key="prokey02">白骨精</prop>
</props>
</property>
</bean>
@Test
public void test03() {
Master master = (Master)applicationContext.getBean("master05");
Properties ps = master.getPs();
System.out.println("ps :"+ps);
for (String key : ps.stringPropertyNames()) {
System.out.println("key:"+key+"value"+ps.getProperty(key));
}
}
八、util名称空间的使用--创建list集合(也可以创建map、set)
注意在xml配置<util-list>标签, 标记粗体的部分
<?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: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">
@Test
public void test04() {
List<String> list = (List<String>)applicationContext.getBean("myList");
for (String string : list) {
System.out.println(string);
}
}
<!-- 创建list-->
<util:list id="myList">
<value>list01-string</value>
<value>list02-string</value>
</util:list>
九、级联属性赋值
实质上是给内嵌的bean的属性赋值
<!-- 级联属性赋值-->
<bean id="myDog" class="com.spring.bean.Dog"/>
<bean id="myBoy" class="com.spring.bean.myBoy">
<property name="name" value="TOM"/>
<property name="dog" ref="myDog"/>
<property name="Dog.name" value="哈巴狗"/>
</bean>
public class myBoy {
private String name;
private Dog dog;
public myBoy() {
}
@Test
public void test05() {
myBoy myBoy = (myBoy)applicationContext.getBean("myBoy");
System.out.println(myBoy.getDog().getName());
}
十、静态工厂获取bean对象
静态工厂类(使用静态的方式生产(new)对象)
public class MyStaticFactory {
private static Map<String,Monster> monster_map;
static {
monster_map = new HashMap<String,Monster>();
monster_map.put("monster01",new Monster(700,"大鱼怪","喝水"));
monster_map.put("monster02",new Monster(800,"小鱼怪","喝水"));
}
public static Monster getMonster(String key){
return monster_map.get(key);
}
}
<!-- 通过静态工厂获取bean-->
<bean id="myMonster" class="com.spring.bean.MyStaticFactory"
factory-method="getMonster"> //指定获取对象的静态方法
<constructor-arg value="monster01"/> //指定获取的key值
</bean>
@Test
public void test06() {
Monster monster = (Monster)applicationContext.getBean("myMonster");
System.out.println(monster); //静态工厂获取bean对象,最终返回的不是静态工厂类,而是生产的对象
}
十一、实例工厂配置bean
public class MyInstanceFactory {
private HashMap<String,Monster> map;
{
map = new HashMap<String,Monster>();
map.put("monsterkey01",new Monster(100,"小鱼怪","喝水"));
map.put("monsterkey02",new Monster(900,"大鱼怪","喝很多水"));
}
public Monster getMonster(String key) {
return map.get(key);
}
}
<!-- 通过实例工厂获取bean-->
<bean id="myInstanceFactory" class="com.spring.bean.MyInstanceFactory"/>
<bean id="monster2" factory-bean="myInstanceFactory" factory-method="getMonster">
<constructor-arg value="monsterkey02"/>
</bean>
/**
* 实例工厂配置bean
*/
@Test
public void test07() {
Monster monster = (Monster) applicationContext.getBean("monster2");
System.out.println(monster);
}
十二、FactoryBean工厂获取bean对象
使用spring提供的FactoryBean<T>接口,可以简化使用工厂bean时spring容器bean.xml的配置,又可以配置是否单例(即在同一个线程中取得的对象总是同一个)
public class MyFactoryBean implements FactoryBean<Monster> {
private String keyval;
private HashMap<String,Monster> map;
{
map = new HashMap<String,Monster>();
map.put("monsterkey01",new Monster(100,"小mao怪","喝水"));
map.put("monsterkey02",new Monster(900,"大猫怪","喝很多水"));
}
/**
* 必需写keyval的getter,setter方法,这是规范
* @return
*/
public String getKeyval() {
return keyval;
}
public void setKeyval(String keyval) {
this.keyval = keyval;
}
/**
* 底层会先调用setKeyval()方法
* @return
* @throws Exception
*/
@Override
public Monster getObject() throws Exception {
return map.get(keyval);
}
@Override
public Class<?> getObjectType() {
return Monster.class;
}
/**
* 在单个线程中,获取bean永远是同一个对象
* @return
*/
@Override
public boolean isSingleton() {
return true;
}
}
<!--使用FactoryBean配置-->
<bean id="monster3" class="com.spring.bean.MyFactoryBean">
<property name="keyval" value="monsterkey02"/>
</bean>
/**
* 使用FactoryBean接口配置实例工厂bean
*/
@Test
public void test08() {
Monster monster = (Monster) applicationContext.getBean("monster3");
System.out.println(monster);
}
十三、bean信息的重用(类似于继承)
1、设置bean的parent属性
<bean id="monstr01" class="com.spring.bean.Monster">
<property name="id" value="100"/>
<property name="nickName" value="牛魔王"/>
<property name="skill" value="芭蕉扇"/>
</bean>
<!--bean信息的重用-->
<bean id="monstr20" class="com.spring.bean.Monster" parent="monstr01"/>
2、可以重写属性 值
<bean id="monstr01" class="com.spring.bean.Monster">
<property name="id" value="100"/>
<property name="nickName" value="牛魔王"/>
<property name="skill" value="芭蕉扇"/>
</bean>
<!--bean信息的重用-->
<bean id="20" class="com.spring.bean.Monster" parent="monstr01">
<property name="nickName" value="200"/>
</bean>
3、如果希望monstr01这个bean不用实例化,只是被用于bean信息重用,那么设置abstract属性为true
<bean id="monstr30" class="com.spring.bean.Monster" abstract="true">
<property name="id" value="100"/>
<property name="nickName" value="牛魔王"/>
<property name="skill" value="芭蕉扇"/>
</bean>
<!--bean信息的重用-->
<bean id="monstr20" class="com.spring.bean.Monster" parent="monstr30">
<property name="id" value="200"/>
</bean>
十四、bean的创建顺序问题
在spring的ioc容器,在默认情况下是按照配置的顺序来创建的比如
<bean id="student01"class="com.itbull.bean.Student"/>
<bean id="department01"class="com.itbull.bean.Department"/>
会先创建student01这个bean对象,然后创建department01这个bean
但是,如果这样配置
<bean id="student01"class="com.itbull.bean.Student" depends-on="department01"/><bean id="department01" class="com.itbull.bean.Department"/>
就会先创建department01bean,再创建student01这个bean.
说明
1.默认情况下是按照顺序来创建bean
2.如果确实有依赖关系,你以通过调整顺序或者使用 depends-on来说明
十五、bean单实例与多实例的说明(重点)
在spring的ioc容器,在默认情况下是按照单例创建的,即配置一个bean对象后,ioc容器只会创建一个bean实例。
如果,我们希望ioc容器配置的某个bean对象,是以多个实例形式创建的则可以通过配置scope="prototype"来指定
<bean id="monstr21" class="com.spring.bean.Monster" scope="prototype"/>
@Test
public void test08() {
Monster monster1 = (Monster) applicationContext.getBean("monstr21");
Monster monster2 = (Monster) applicationContext.getBean("monstr21");
System.out.println(monster1.hashCode());
System.out.println(monster2.hashCode());
}
细节说明:
1.默认是单例,当<bean scope="prototype">设置为多实例机制
2.设置为scope="prototype"后,该bean是在getBean时才创建。
十六、配置有生命周期的bean
每个bean都会有一个初始化,销毁的过程。配置有生命周期的bean,即可以在初始化与销毁的时点做些事儿
public class Cat {
private String name;
public Cat() {
System.out.println("cat无参构造方法被调用");
}
public Cat(String name) {
this.name = name;
System.out.println("cat有参构造方法被调用");
}
public void init() {
System.out.println("小猫被初始化了,取名叫小黄");
}
public void play() {
System.out.println(this.name+"正在快乐地玩耍");
}
public void destroy() {
System.out.println(this.name+"活了一百岁,安息");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<!-- 配置有生命周期的bean-->
<bean id="cat1" class="com.spring.bean.Cat" init-method="init" destroy-method="destroy">
<property name="name" value="宝宝"/>
</bean>
@Test
public void test08() {
Cat cat1 = (Cat) applicationContext.getBean("cat1");
cat1.play();
ConfigurableApplicationContext cac = (ConfigurableApplicationContext) applicationContext;
cac.close();
System.out.println("程序没有退出");
}
十七、配置后置处理器
如果在IOC容器中bean配置了init()方法(什么是init方法请看十五),此时希望可以在init()方法被调用的前后做一些设置比如记录日志,或者过滤,那么可以考虑使用后置处理器。
具体用法如下
十八、通过属性文件注入值
之前在学习集合时,学习过map接口的实现类properties类,可以将例如JDBC的配置信息写在.properties文件中。
1、在源码目录src下,new一个File文件,取名my.properties,写上monster类的键值对
2、配置xml标签声明
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=“http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">”
在bean.xml中引用
<!--通过属性文件注入值-->
<context:property-placeholder location="classpath:my.properties"/>
<bean id="monster99" class="com.spring.bean.Monster">
<property name="id" value="${monster.id}"/>
<property name="nickName" value="${monster.name}"/>
<property name="skill" value="${monster.skill}"/>
</bean>
3、
/**
*通过属性文件注入值
*/
@Test
public void test09() {
Monster monster = (Monster) applicationContext.getBean("monster99");
System.out.println(monster.toString());
}
十九、 Spring基于xml自动装配bean
当Action-service-Dao三层架构的情况下,如果不使用ref如何配置bean.xml呢?使用bean的autowire属性,来配置
具体说明:
1、先看一个传统SSH框架的Action-service-Dao的写法(ref)
public class OrderDao {
public void save(){
System.out.println("save了一个对象");
}
public OrderDao() {
}
}
import com.spring.orderDao.OrderDao;
public class OrderService {
private OrderDao orderDao;
public OrderService() {
}
public OrderDao getOrderDao() {
return orderDao;
}
public void setOrderDao(OrderDao orderDao) {
this.orderDao = orderDao;
}
public void save(){
orderDao.save();
}
}
import com.spring.orderService.OrderService;
public class OrderAcion {
private OrderService orderService;
public OrderAcion() {
}
public OrderService getOrderService() {
return orderService;
}
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
public void save() {
orderService.save();
}
}
<!-- 传统方式配置Action-Service-Dao-->
<bean id="orderDao" class="com.spring.orderDao.OrderDao" />
<bean id="orderService" class="com.spring.orderService.OrderService">
<property name="orderDao" ref="orderDao"/>
</bean>
<bean id="orderAction" class="com.spring.orderAction.OrderAcion">
<property name="orderService" ref="orderService"/>
</bean>
/**
*通过属性文件注入值
*/
@Test
public void test10() {
OrderAcion orderAcion = (OrderAcion) applicationContext.getBean("orderAction");
orderAcion.save();
}
2、spring基于xml的自动装配
(1)利用bean的autowire="byType"。
1>spring 容器先构造了orderDao
2>
在spring容器构造orderService时发现有autowire="byType",那么就会去看orderService类有什么类需要装配即有什么属性是对象类的,然后j将orderDao装配给orderService.
3>“装配”最终表现为, OrderAcion orderAcion = (OrderAcion) applicationContext.getBean("orderAction");
orderAcion.save(); 输出为 save了一个对象
<!-- spring基于xml的自动装配1-->
<bean id="orderDao" class="com.spring.orderDao.OrderDao"/>
<bean id="orderService" autowire="byType" class="com.spring.orderService.OrderService"/>
<bean id="orderAction" autowire="byType" class="com.spring.orderAction.OrderAcion"/>
(2)方式一bytype只能是当orderDao只有一个bean时使用,当多个orderDao的bean时,使用byname。
注意byName的依据是 orderService的 setOrderDao2方法, 即orderService的这个set方法名称与bean id="orderDao2"相同
<!-- spring基于xml的自动装配2-->
<bean id="orderDao2" class="com.spring.orderDao.OrderDao"/>
<bean id="orderService" autowire="byName" class="com.spring.orderService.OrderService"/>
<bean id="orderAction" autowire="byName" class="com.spring.orderAction.OrderAcion"/>
辅助说明
二十、使用spel表达式为属性赋值
spel表达式公式: #{spel公式}
<!-- 使用spel表达式为属性赋值-->
<bean id="spelBean" class="com.spring.bean.SpelBean">
<!-- 使用字面量赋值-->
<property name="beanName" value="#{'snowdream雪'}"/>
<!-- 使用其他bean的属性赋值-->
<property name="monsterName" value="#{monstr01.nickName}"/>
<!-- 直接使用其他bean赋值-->
<property name="monster" value="#{monstr02}"/>
<!-- 使用方法的返回值赋值-->
<property name="result" value="#{spelBean.getSum(2.0,3.0)}"/>
<!-- 使用静态方法的返回值赋值-->
<property name="bookName" value="#{T(com.spring.bean.SpelBean).readBook('爱你一万年')}"/>
</bean>
public class SpelBean {
//在spring容器中,使用Spel表达式来给属性赋值
private String beanName;
private String monsterName;
private Monster monster;
private Double result;
private String bookName;
public SpelBean() {
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public String getMonsterName() {
return monsterName;
}
public void setMonsterName(String monsterName) {
this.monsterName = monsterName;
}
public Monster getMonster() {
return monster;
}
public void setMonster(Monster monster) {
this.monster = monster;
}
public Double getResult() {
return result;
}
public void setResult(Double result) {
this.result = result;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public SpelBean(String beanName, String monsterName, Monster monster, Double result, String bookName) {
this.beanName = beanName;
this.monsterName = monsterName;
this.monster = monster;
this.result = result;
this.bookName = bookName;
}
public Double getSum(double a,double b) {
return a+b;
}
public static String readBook(String s) {
return s;
}
@Override
public String toString() {
return "SpelBean{" +
"beanName='" + beanName + '\'' +
", monsterName='" + monsterName + '\'' +
", monster=" + monster +
", result=" + result +
", bookName='" + bookName + '\'' +
'}';
}
}
/**
* 使用spel表达式赋值
*/
@Test
public void test11() {
SpelBean spelBean = (SpelBean) applicationContext.getBean("spelBean");
System.out.println(spelBean);
}