Spring管理Bean-IOC-02

2.基于XML配置bean

2.7通过util空间名称创建list

BookStore.java:

package com.li.bean;

import java.util.List;

/**
* @author 李
* @version 1.0
*/
public class BookStore {
private List<String> bookList; //如果类中没有其他构造器,默认构造器可以不写
// 如果有其他构造器,则必须显示定义无参构造器
public BookStore() {
} public List<String> getBookList() {
return bookList;
} public void setBookList(List<String> bookList) {
this.bookList = bookList;
} @Override
public String toString() {
return "BookStore{" +
"bookList=" + bookList +
'}';
}
}

如果有多个BookStore对象,list的内容都一样,按照之前的做法,每一个list都要写上相同的value值。但使用util命名空间可以达到数据复用的效果。

beans.xml:

<!--定义util:list,并指定id,可以达到数据复用的效果-->
<util:list id="myBookList">
<value>三国演义</value>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
</util:list> <!--配置BookStores对象-->
<bean class="com.li.bean.BookStore" id="bookStore">
<property name="bookList" ref="myBookList"/>
</bean>

注意引入util命名空间,一般来说ide会有提示,如果没有则按如下引入:

SpringBeanTest:

package com.li.test;

import com.li.bean.BookStore;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test; /**
* @author 李
* @version 1.0
*/
public class SpringBeanTest { //使用util:list名称空间给属性赋值
@Test
public void setBeanByUtilList() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
BookStore bookStore = ioc.getBean("bookStore", BookStore.class);
System.out.println("bookStore=" + bookStore);
}
}

2.8级联属性赋值

  1. 案例说明:spring的ioc容器,可以直接给对象属性的属性赋值,即级联属性赋值

  2. 完成步骤:

    (1)创建Dept.java和Emp.java

    (2)配置beans.xml


Dept.java:

package com.li.bean;

/**
* @author 李
* @version 1.0
* 部门类
*/
public class Dept {
private String name; public Dept() {
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Dept{" +
"name='" + name + '\'' +
'}';
}
}

Emp.java:

package com.li.bean;

/**
* @author 李
* @version 1.0
* 员工类
*/
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;
} @Override
public String toString() {
return "Emp{" +
"name='" + name + '\'' +
", dept=" + dept +
'}';
}
}

beans.xml:

<!--配置Dept对象-->
<bean class="com.li.bean.Dept" id="dept"/>
<!--配置Emp对象-->
<bean class="com.li.bean.Emp" id="emp">
<property name="name" value="jack"/>
<property name="dept" ref="dept"/>
<!--这里我希望给dept的name属性赋值[级联属性赋值]-->
<property name="dept.name" value="Java开发部门"/>
</bean>

SpringBeanTest:

package com.li.test;

import com.li.bean.Emp;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test; /**
* @author 李
* @version 1.0
*/
public class SpringBeanTest { //使用级联赋值给属性的属性赋值
@Test
public void setBeanByRelation() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Emp emp = ioc.getBean("emp", Emp.class);
System.out.println("emp=" + emp);
}
}

2.9通过静态工厂获取对象

  1. 在spring的ioc容器,可以通过静态工厂获取bean对象

  2. 完成步骤:

    (1)静态工厂类MyStaticFactory类和Monster类

    (2)配置beans.xml


Monster类详见上一篇--2.1通过类型来获取bean

MyStaticFactory.java:

package com.li.factory;

import com.li.bean.Monster;

import java.util.HashMap;
import java.util.Map; /**
* @author 李
* @version 1.0
* 静态工厂类-可以返回Monster对象
*/
public class MyStaticFactory {
private static Map<String, Monster> monsterMap; //使用static静态代码块进行初始化
// (静态代码块在类加载的同时就直接执行,且只执行一次)
static {
monsterMap = new HashMap<>();
monsterMap.put("monster01", new Monster(100, "孙悟空", "七十二变"));
monsterMap.put("monster02", new Monster(200, "金蝉子", "普渡众生"));
} //提供一个方法,返回monster对象
public static Monster getMonster(String key) {
return monsterMap.get(key);
}
}

beans.xml:

<!--配置monster,通过静态工厂获取
1.通过静态工厂配置bean
2.class不再是monster的路径,而是静态工厂的全路径
3.factory-method 表示指定静态工厂的哪个方法来返回对象
4.constructor-arg value="monster02" 指定要返回静态工厂的哪个对象
-->
<bean id="my_monster01" class="com.li.factory.MyStaticFactory" factory-method="getMonster">
<constructor-arg value="monster02"/>
</bean>

SpringBeanTest:

package com.li.test;

import com.li.bean.Monster;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test; /**
* @author 李
* @version 1.0
*/
public class SpringBeanTest { //使用静态工厂来获取 bean
@Test
public void getBeanByStaticFactory() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster my_monster01 = ioc.getBean("my_monster01", Monster.class);
//这里如果使用的是相同id获取bean,那么获取的实际上是同一个对象,例如:
Monster my_monster001 = ioc.getBean("my_monster01", Monster.class);
// 因为静态工厂中的静态代码块只执行一次,这里不同的对象引用指向的都是同一个对象
System.out.println(my_monster01 == my_monster001);//true System.out.println("my_monster01=" + my_monster01);
}
}

2.10通过实例工厂获取对象

Monster类详见上一篇--2.1通过类型来获取bean

MyInstanceFactory:

package com.li.factory;

import com.li.bean.Monster;

import java.util.HashMap;
import java.util.Map; /**
* @author 李
* @version 1.0
* 实例工厂类
*/
public class MyInstanceFactory {
private Map<String, Monster> monster_map; //通过普通代码块进行初始化
//普通代码块每创建一个对象就会执行一次
{
monster_map = new HashMap<>();
monster_map.put("monster03", new Monster(300, "猪八戒", "九尺钉耙"));
monster_map.put("monster04", new Monster(400, "沙和尚", "丈二禅杖"));
} //写一个方法返回Monster对象
public Monster getMonster(String key) {
return monster_map.get(key);
}
}

beans.xml:

<!--因为是实例工厂对象,所以需要配置才能使用(静态工厂可以直接使用不用配置)-->
<bean class="com.li.factory.MyInstanceFactory" id="myInstanceFactory"/>
<bean class="com.li.factory.MyInstanceFactory" id="myInstanceFactory02"/> <!--配置monster,通过实例工厂获取
1.factory-bean 表示使用哪个实例工厂对象返回bean
2.factory-method 指定使用实例工厂对象的哪个方法返回bean
3.constructor-arg value="monster03" 指定获取实例工厂中的哪个对象
-->
<bean id="my_monster02" factory-bean="myInstanceFactory" factory-method="getMonster">
<constructor-arg value="monster03"/>
</bean> <bean id="my_monster03" factory-bean="myInstanceFactory02" factory-method="getMonster">
<constructor-arg value="monster03"/>
</bean>

SpringBeanTest:

package com.li.test;

import com.li.bean.Monster;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test; /**
* @author 李
* @version 1.0
*/
public class SpringBeanTest { //使用实例工厂来获取 bean
@Test
public void getBeanByInstanceFactory() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); Monster my_monster02 = ioc.getBean("my_monster02", Monster.class);
System.out.println("my_monster02=" + my_monster02); // 这里使用相同的id获取bean,那么返回的对象也是同一个!!
Monster my_monster002 = ioc.getBean("my_monster02", Monster.class);
// 因为虽然是实例工厂,但是两次 ioc.getBean("my_monster02", Monster.class)使用的都是
// 同一个工厂实例(id="myInstanceFactory"),返回的自然也就是同一个实例工厂中的 monster
System.out.println(my_monster02 == my_monster002);//true //换而言之,如果不是同一个实例工厂,那么返回的就不是同一个对象了
//(这里的my_monster03,在beans.xml使用的是 id=myInstanceFactory02的实例工厂)
Monster my_monster03 = ioc.getBean("my_monster03", Monster.class);
System.out.println("my_monster03=" + my_monster03);
System.out.println(my_monster02 == my_monster03);//false
}
}

2.11通过FactoryBean获取对象(重点)

在spring的ioc容器,通过FactoryBean获取bean对象

MyFactoryBean:

package com.li.factory;

import com.li.bean.Monster;
import org.springframework.beans.factory.FactoryBean; import java.util.HashMap;
import java.util.Map; /**
* @author 李
* @version 1.0
* FactoryBean
*/
public class MyFactoryBean implements FactoryBean<Monster> {
//这个就是你配置的时候,指定要获取的对象对应的key
private String key;
private Map<String, Monster> monster_map; //代码块完成初始化
{
monster_map = new HashMap<>();
monster_map.put("monster05", new Monster(5, "黑风怪", "翻江倒海"));
monster_map.put("monster06", new Monster(6, "金角大王", "超能力"));
} public void setKey(String key) {
this.key = key;
} @Override
public Monster getObject() throws Exception {
return monster_map.get(key);
} @Override
public Class<?> getObjectType() {
return Monster.class;
} @Override
public boolean isSingleton() {//这里指定是否是单例对象
return true;
}
}

beans.xml:

<!--配置monster对象,通过FactoryBean来获取
1.这里的class 指定要使用的FactoryBean
2.key是 你设置的FactoryBean的属性key
3.value 就是你要获取的对象的对应 key
-->
<bean id="my_monster05" class="com.li.factory.MyFactoryBean">
<property name="key" value="monster05"/>
</bean>

SpringBeanTest:

package com.li.test;

import com.li.bean.Monster;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test; /**
* @author 李
* @version 1.0
*/
public class SpringBeanTest {
//通过FactoryBean获取bean对象
@Test
public void getBeanByFactoryBean() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster my_monster05 = ioc.getBean("my_monster05", Monster.class);
System.out.println("my_monster05=" + my_monster05);
}
}

2.12bean配置信息重用(继承)

在spring的ioc容器中,提供了一种继承的方式来实现bean配置信息的重用

beans.xml:

<!--配置Monster对象-->
<bean class="com.li.bean.Monster" id="monster10">
<property name="monsterId" value="10"/>
<property name="name" value="蜈蚣精"/>
<property name="skill" value="蜇人"/>
</bean> <!--现在配置另一个Monster对象,
1.这个对象的属性值 和 id="monster10"对象属性一样
2.parent="monster10" 指定当前这个配置的对象的属性值从id=monster10的对象来
-->
<bean id="monster11" class="com.li.bean.Monster" parent="monster10"/>

SpringBeanTest:

package com.li.test;

import com.li.bean.Monster;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test; /**
* @author 李
* @version 1.0
*/
public class SpringBeanTest { //配置Bean(通过继承)
@Test
public void getBeanByFactoryBean() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster monster10 = ioc.getBean("monster10", Monster.class);
Monster monster11 = ioc.getBean("monster11", Monster.class); System.out.println("monster10=" + monster10);
System.out.println("monster11=" + monster11);
}
}

注意:

  1. 如果bean指定了abstract="true" 表示该bean对象是只用于被继承的

  2. 那么这个bean就不能被获取/实例化

此时如果输出monster10,就会显示错误:

2.13bean创建顺序

在spring的ioc容器,默认是按照配置的顺序创建bean对象。比如:

<bean id="student01" class="com.hspedu.bean.Student" />
<bean id="department01" class="com.hspedu.bean.Department" />

会先创建 student01 这个 bean 对象,然后创建 department01 这个 bean 对象

但如果这样配置:

<bean id="student01" class="com.hspedu.bean.Student" depends-on="department01"/>
<bean id="department01" class="com.hspedu.bean.Department" />

会先创建 department01 对象,再创建 student01 对象.

例子

Student:

package com.li.bean;

/**
* @author 李
* @version 1.0
*/
public class Student {
public Student() {
System.out.println("Student 构造器被执行...");
}
}

Department:

package com.li.bean;

/**
* @author 李
* @version 1.0
*/
public class Department {
public Department() {
System.out.println("Department 构造器被执行...");
}
}

beans.xml:

<!--测试 bean对象的创建顺序-->
<bean id="student01" class="com.li.bean.Student"/>
<bean id="department01" class="com.li.bean.Department"/>

测试类:

//测试 Bean的创建顺序
@Test
public void testBeanByCreate() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
System.out.println("ok~");
}

如果我们在配置student01对象时,加上depends-on="department01",spring就会认为你的student01对象时依赖于department01对象,会先创建department01对象。

<bean id="student01" class="com.hspedu.bean.Student" depends-on="department01"/>
<bean id="department01" class="com.hspedu.bean.Department" />

总结:在默认情况下,bean创建的顺序是按照默认配置顺序来的。但是如果我们在对象配置中指定了依赖对象,就会先创建被依赖的对象。

一个问题?

1.先看下面的配置,请问两个bean创建的顺序是什么?并分析执行流程

<!--配置MemberDAOImpl对象-->
<bean class="com.li.dao.MemberDAOImpl" id="memberDAOImpl"/> <bean class="com.li.service.MemberServiceImpl" id="memberServiceImpl">
<property name="memberDAO" ref="memberDAOImpl"/>
</bean>

(1)先创建 id=memberDaoImpl 的对象

(2)再创建 id=memberServiceImpl 的对象

(3)调用 memberServiceImpl.setMemberDAO() 方法,完成引用

2.先看下面的配置,请问两个bean创建的顺序是什么?并分析执行流程

<bean class="com.li.service.MemberServiceImpl" id="memberServiceImpl">
<property name="memberDAO" ref="memberDAOImpl"/>
</bean> <!--配置MemberDAOImpl对象-->
<bean class="com.li.dao.MemberDAOImpl" id="memberDAOImpl"/>

(1)先创建 id=memberServiceImpl 的对象

(2)再创建 id=memberDaoImpl 的对象

(3)调用 memberServiceImpl.setMemberDAO() 方法,完成引用

总结:ioc容器会把整个bean的创建当做一个整体来对待,会把配置文件中所有对象bean先创建好,然后才完成对象间的引用。

见2.4

2.14bean对象的单例和多例

在spring的ioc容器中,默认是按照单例创建的,即配置一个bean对象后,ioc容器只会创建一个bean实例。

如果希望ioc容器配置的某个bean对象,是以多个实例形式创建的,可以通过配置scope="prototype"来指定。

例子1-单例对象

Cat:

package com.li.bean;

/**
* @author 李
* @version 1.0
*/
public class Cat {
private Integer id;
private String name; public Cat() {
System.out.println("Cat() 构造器被执行...");
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

beans.xml:

<!--配置 Cat对象
1.默认情况下,scope属性的值为 "singleton",即ioc容器中只会有一个这样的bean对象
当执行getBean时,返回的是同一个对象
2.如果希望每次使用getBean都返回新的Bean对象,就要把scope的属性设为 prototype
-->
<bean id="cat" class="com.li.bean.Cat">
<property name="id" value="10"/>
<property name="name" value="小花猫"/>
</bean>

测试类:

//测试Scope
@Test
public void testBeanScope() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Cat cat1 = ioc.getBean("cat", Cat.class);
Cat cat2 = ioc.getBean("cat", Cat.class);
Cat cat3 = ioc.getBean("cat", Cat.class);
System.out.println("cat1="+cat1);
System.out.println("cat2="+cat2);
System.out.println("cat3="+cat3);
}

输出如下:地址值相同,证明这三个对象引用都指向了同一个对象

例子2-多例对象

现在我们把例子1的cat对象的配置改为scope="prototype"

<bean id="cat" class="com.li.bean.Cat" scope="prototype">
<property name="id" value="10"/>
<property name="name" value="小花猫"/>
</bean>

输出如下:构造器执行了三次,说明创建了三个Cat对象(对象的地址值也不一样)

使用细节

  1. 当bean为scope="singleton"(默认值),在启动容器时,就会创建单例对象,并放入singletonObjects集合

  2. 当bean设置为scope="prototype",即设置为多实例机制后,该bean是在getBean时才创建

  3. 如果是单例singleton,但又希望在getBean时才创建,可以指定懒加载lazy-init="true" (默认值是false)

  4. 通常情况下,lazy-init 使用默认值false,因为在开发看来,用空间换时间是值得的,除非有特殊要求。

  5. 如果scope="prototype",这时你的lazy-init属性值不管设置为什么,都默认为true

    因为多例情况下,spring无法知道创建几个对象,因此只有在用到的时候才能创建

day04-Spring管理Bean-IOC-02的更多相关文章

  1. (转)编码剖析Spring管理Bean的原理

    http://blog.csdn.net/yerenyuan_pku/article/details/52832434 在Spring的第一个案例中,我们已经知道了怎么将bean交给Spring容器进 ...

  2. 采用Spring管理Bean和依赖注入

    1. 实例化spring容器和从容器获取Bean对象 实例化Spring容器常用的两种方式: 方法一: 在类路径下寻找配置文件来实例化容器 [推荐使用] ApplicationContext ctx ...

  3. Spring管理bean的生命周期

    1: bean的创建:   如果我们默认的scope配置为Singleton的话, bean的创建实在Spring容器创建的时候创建: 如果scope的配置为Prototype的话,bena的创建是在 ...

  4. Spring、编码剖析Spring管理Bean的原理

    引入dom4j jar包 1.新建Person接口和PersonBean public interface PersonIService { public void helloSpring(); } ...

  5. Spring第三弹—–编码剖析Spring管理Bean的原理

    先附一下编写的Spring容器的执行结果: 代码如下: 模拟的Spring容器类:   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ...

  6. Spring——管理Bean的生命周期

    我们可以自定义bean的初始化和销毁方法,这里所指的的初始化和bean的构造不同,初始化是在bean构造完成后,对bean内部的属性或一些逻辑进行初始化. 首先要弄清一些概念: 构造(对象创建) 单实 ...

  7. 编码剖析Spring管理bean的原理

    project目录 MyClassPathXMLApplicationContext读取xml,以及实例化bean. 因为是一开始实例化配置文件所有bean,所以需要构造器完成这些工作. packag ...

  8. Spring管理Bean的三种创建方式

    1.使用类构造器实例化  (90%以上都是使用这种) <bean id=“orderService" class="cn.itcast.OrderServiceBean&qu ...

  9. 简单模拟Spring管理Bean对象

    1: 首先我们要利用dom4j进行xml的解析,将所有的bean的配置读取出来. 2:利用java的反射机制进行对象的实例化. 3: 直接获得对象 package cn.Junit.test; imp ...

  10. spring 管理bean

    目录结构: Person.java package com.wss.entity; import com.wss.service.doHomeWork; public class Person { p ...

随机推荐

  1. 七、Ajax请求

    七.Ajax请求 客户端(浏览器)向服务端发起请求的形式: 地址栏:GET 超链接标签:GET form表单:GET或POST Ajax(重要):GET或POST或PUT或DELETE AJAX(As ...

  2. element-plus 消息提示

    用来显示「成功.警告.消息.错误」类的操作 <template> <el-button :plain="true" @click="open2" ...

  3. iphoneApp Fidder设置

    使用iphone 打开fidder 按照如上配置 安装完毕 然后访问计算机地址- 比如我的计算机ip地址是 192.168.2.10那么我需要在我的safari浏览器中输入192.168.2.10:8 ...

  4. 在博客中实现播放音乐功能(QQ,网易,酷狗,虾米,百度)

    1.在页头head标签里添加: <link rel="stylesheet" href="https://static.likepoems.com/cdn/apla ...

  5. 用Nodejs 实现一个简单的 Redis客户端

    目录 0. 写在前面 1. 背景映入 2. 数据库选择 3. Nodejs TCP连接 3. 代码编写 4. 实验 5. wireshark 抓包分析 6. 杂与代码 0. 写在前面 大家如果有去看过 ...

  6. Pyside2 开发框架

    apps文件夹 tools文件夹 Main.py .ui .json Global.py Main.py 通用 函数及子线程 函数内容

  7. OpenHarmony移植案例: build lite源码分析之hb命令__entry__.py

    摘要:本文介绍了build lite 轻量级编译构建系统hb命令的源码,主要分析了_\entry__.py文件. 本文分享自华为云社区<移植案例与原理 - build lite源码分析 之 hb ...

  8. 视频服务HDR Vivid 还原色彩,让所见成“真”

    如今,视频正在以一种前所未有的方式渗入日常生活,是当下人们记录生活最热门的方式.所以,用户对视频的画质要求越来越高,App想要吸引更多的用户,拥有视频画质新技术的强力支撑很关键. HDR(High-D ...

  9. Pairs of Numbers 辗转相除

    # 42. Pairs of Numbershttps://blog.csdn.net/qq_43521140/article/details/107853492- 出题人:OJ- 标签:[" ...

  10. 二叉树总结——BiTree

    在C++编译器下可直接运行 #include <stdio.h> #include <malloc.h> //算法思想:先读入根结点数据,并且创建根结点,在读入左子树数据并创建 ...