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. 学习ASP.NET Core Blazor编程系列九——服务器端校验

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  2. 用map来统计数组中各个字符串的数量

    1.背景 想要统计这一个字符串数组中每一个非重复字符串的数量,使用map来保存其key和value.这个需求在实际开发中经常使用到,我以前总是新建一个空数组来记录不重复字符串,并使用计数器计数,效率低 ...

  3. Marktext语法——Emoji表情大全

    个人名片: 对人间的热爱与歌颂,可抵岁月冗长 Github‍:念舒_C.ying CSDN主页️:念舒_C.ying 个人博客 :念舒_C.ying People ️ ️ ️ ️ ‍♀️ ‍♀️ ‍♂ ...

  4. PGL图学习之图神经网络GraphSAGE、GIN图采样算法[系列七]

    0. PGL图学习之图神经网络GraphSAGE.GIN图采样算法[系列七] 本项目链接:https://aistudio.baidu.com/aistudio/projectdetail/50619 ...

  5. 第2-3-7章 个人网盘服务接口开发-文件存储服务系统-nginx/fastDFS/minio/阿里云oss/七牛云oss

    目录 5.8 导入其他接口代码 5.8.1 接口导入-分页查询附件 5.8.2 接口导入-根据业务类型/业务id查询附件 5.9 导入网盘服务接口 5.9.1 导入FileController 5.9 ...

  6. 视觉享受,兼顾人文观感和几何特征的字体「GitHub 热点速览 v.22.46」

    GitHub 上开源的字体不在少数,但是支持汉字以及其他非英文语言的字体少之又少,记得上一个字体还是 霞鹜文楷,本周 B 站知名设计 UP 主开源了的得意黑体在人文观感和几何特征之间找到了美的平衡. ...

  7. i春秋Blog

    打开是个普普通通的hello world 然后有注册有登录 不多说我们直接注册登录试试 登录后有个POST选项,可以上传东西,先试试上传文字 没什么重要的回显 再上传一个文档试试 爆出提示:这里使用的 ...

  8. MyBatis-Plus 分页插件过时

    引用:https://blog.csdn.net/zyw562123314/article/details/108903456//分页插件老版本过时 旧版本配置 @Bean public Pagina ...

  9. Selenium4+Python3系列(十) - Page Object设计模式

    前言 Page Object(PO)模式,是Selenium实战中最为流行,并且被自动化测试同学所熟悉和推崇的一种设计模式之一.在设计测试时,把页面元素定位和元素操作方法按照页面抽象出来,分离成一定的 ...

  10. 2A锂电池充电管理IC,具有恒压/恒流充电模式

    PW4052 是一颗适用于单节锂电池的.具有恒压/恒流充电模式的充电管理 IC.该芯片采用开关型的工作模 式, 能够为单节锂电池提供快速. 高效且简单的充电管理解决方案. PW4052 采用三段式充电 ...