草庐IT

day04-Spring管理Bean-IOC-02

liyuelian 2023-04-16 原文

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命名空间:

测试类:

//使用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>

测试类:

//使用级联赋值给属性的属性赋值
@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>

测试类:

//使用静态工厂来获取 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>

测试类:

//使用实例工厂来获取 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>

测试类:

//通过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"/>

测试类:

//配置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. ruby-on-rails - 带 Spring 锁的 Rails 4 控制台 - 2

    我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.

  2. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  3. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  4. 牛客网专项练习30天Pytnon篇第02天 - 2

    1.在Python3中,下列关于数学运算结果正确的是:(B)a=10b=3print(a//b)print(a%b)print(a/b)A.3,3,3.3333...B.3,1,3.3333...C.3.3333...,3.3333...,3D.3.3333...,1,3.3333...解析:    在Python中,//表示地板除(向下取整),%表示取余,/表示除(Python2向下取整返回3)2.如下程序Python2会打印多少个数:(D)k=1000whilek>1:    print(k)k=k/2A.1000 B.10C.11D.9解析:    按照题意每次循环K/2,直到K值小于等

  5. spring.profiles.active和spring.profiles.include的使用及区别说明 - 2

    转自:spring.profiles.active和spring.profiles.include的使用及区别说明下文笔者讲述spring.profiles.active和spring.profiles.include的区别简介说明,如下所示我们都知道,在日常开发中,开发|测试|生产环境都拥有不同的配置信息如:jdbc地址、ip、端口等此时为了避免每次都修改全部信息,我们则可以采用以上的属性处理此类异常spring.profiles.active属性例:配置文件,可使用以下方式定义application-${profile}.properties开发环境配置文件:application-dev

  6. ruby - 在 Ubuntu 14.04 中使用 Curl 安装 RVM 时出错 - 2

    我试图在Ubuntu14.04中使用Curl安装RVM。我运行了以下命令:\curl-sSLhttps://get.rvm.io|bash-sstable出现如下错误:curl:(7)Failedtoconnecttoget.rvm.ioport80:Networkisunreachable非常感谢解决此问题的任何帮助。谢谢 最佳答案 在执行curl之前尝试这个:echoipv4>>~/.curlrc 关于ruby-在Ubuntu14.04中使用Curl安装RVM时出错,我们在Stack

  7. ruby-on-rails - Spring 不起作用。 [未初始化常量 Spring::SID::DL] - 2

    我无法运行Spring。这是错误日志。myid-no-MacBook-Pro:myid$spring/Users/myid/.rbenv/versions/1.9.3-p484/lib/ruby/gems/1.9.1/gems/spring-0.0.10/lib/spring/sid.rb:17:in`fiddle_func':uninitializedconstantSpring::SID::DL(NameError)from/Users/myid/.rbenv/versions/1.9.3-p484/lib/ruby/gems/1.9.1/gems/spring-0.0.10/li

  8. ruby-on-rails - rails : Find tasks that were created on a certain day? - 2

    我有一个任务列表(名称、starts_at),我试图在每日View中显示它们(就像iCal)。deftodays_tasks(day)Task.find(:all,:conditions=>["starts_atbetween?and?",day.beginning,day.ending]end我不知道如何将Time.now(例如“2009-04-1210:00:00”)动态转换为一天的开始(和结束),以便进行比较。 最佳答案 deftodays_tasks(now=Time.now)Task.find(:all,:conditio

  9. ruby-on-rails - Ubuntu 14.04 Rails 丢失文件 - 2

    安装Rails时,一切都很好,但后来,我写道:rails-v和输出:/home/toshiba/.rvm/rubies/ruby-2.2.1/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in`require':cannotloadsuchfile--rails/cli(LoadError)from/home/toshiba/.rvm/rubies/ruby-2.2.1/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in`r

  10. 什么是0day漏洞?如何预防0day攻击? - 2

    什么是0day漏洞?0day漏洞,是指已经被发现,但是还未被公开,同时官方还没有相关补丁的漏洞;通俗的讲,就是除了黑客,没人知道他的存在,其往往具有很大的突发性、破坏性、致命性。0day漏洞之所以称为0day,正是因为其补丁永远晚于攻击。所以攻击者利用0day漏洞攻击的成功率极高,往往可以达到目的并全身而退,而防守方却一无所知,只有在漏洞公布之后,才后知后觉,却为时已晚。“后知后觉、反应迟钝”就是当前安全防护面对0day攻击的真实写照!为了方便大家理解,中科三方为大家梳理当前安全防护模式下,一个漏洞从发现到解决的三个时间节点:T0:此时漏洞即0day漏洞,是已经被发现,还未被公开,官方还没有相

随机推荐