小工具知识网

当前位置: 首页 > 行业知识 > Spring系列二:基于XML配置bean

行业知识

Spring系列二:基于XML配置bean

2026-11-15 05:40:14 来源:互联网转载

基于XML配置Bean

  • 通过类型获取bean
  • 通过指定构造器配置bean
  • 通过p名称空间配置bean
  • 通过ref配置bean
  • 通过内部bean配置属性
  • 对集合数组属性进行配置
    • 对List属性进行配置
    • 对Map属性进行配置
    • 对Set属性进行配置
    • 对Array属性进行配置
    • 对Properties属性进行配置
    • 使用utillist进行配置
    • 属性级联赋值配置
    • 通过静态工厂获取bean
    • bean配置信息重用
    • bean创建顺序
    • bean的单例和多实例
    • bean的生命周期
    • 配置bean后置处理器
    • 通过属性文件配置bean
    • 基于XML的bean的自动装配
    • Spring El 表���式配置Bean

      上文中, 我们学习到了 Spring系列一:spring的安装与使用

      接下来我们学习, 通过XML配置bean

      依然是 Spring项目

      Bean管理包括两方面: 创建bean对象, 给bean注入属性

      通过类型获取bean

      案例: 通过spring的ioc容器, 获取一个bean对象, 获取方式: 按类型.

                      

      演示通过bean的类型获取对象

      @Testpublic void getBeanByType() {    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");    //直接传入class对象/类型    Monster bean = ioc.getBean(Monster.class);    System.out.println("bean=" + bean);}

      细节

      按照类型获取bean, 要求ioc容器中的同一个类的bean只能有一个, 否则会抛出异常 NoUniqueBeanDefinationException

      这种方式的应用场景: 比如XxxAction / Servlet / Controller, 或XxxService在一个线程中只需要一个对象实例(单例)的情况

      在容器配置文件(比如beans.xml)中给属性赋值. 底层是通过setter方法完成的. 所以需要提供setter方法.

      通过指定构造器配置bean

                                 

      演示通过构造器来设置属性

      @Testpublic void setBeanByConstructor() {    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");    Monster monster03 = ioc.getBean("monster03", Monster.class);    System.out.println("monster03=" + monster03);}

      通过index属性来区分是第几个参数;

      通过type属性来区分是什么类型(按照顺序, 这是可以的)

      通过p名称空间配置bean

      xmlns:p=“http://www.springframework.org/schema/p”

       

      演示通过p名称空间来设置属性

      public class SpringBeanTest {    @Test    public void setBeanByP() {        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");        Monster monster06 = ioc.getBean("monster06", Monster.class);        System.out.println("monster06=" + monster06);    }}

      通过ref配置bean

      引用注入其它bean对象

      在spring的ioc容器, 可以通过ref来实现bean对象的相互引用[ref全称: reference]

          
      package com.zzw.spring.service;public class MemberServiceImpl {    private MemberDaoImpl memberDao;    public MemberDaoImpl getMemberDao() {        return memberDao;    }    public void setMemberDao(MemberDaoImpl memberDao) {        this.memberDao = memberDao;    }    public void add() {        System.out.println("MemberServiceImpl add方法被调用...");        memberDao.add();    }}
      package com.zzw.spring.dao;public class MemberDaoImpl {    public MemberDaoImpl() {        System.out.println("MemberDaoImpl 构造器...");    }    public void add() {        System.out.println("MemberDaoImpl add方法被执行");    }}

      测试: 通过ref来设置bean属性

      public class SpringBeanTest {    @Test    public void setBeanByRef() {        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");        MemberServiceImpl memberService = ioc.getBean("memberService", MemberServiceImpl.class);        memberService.add();    }}

      通过内部bean配置属性

      引用/注入内部bean对象

      在spring的ioc容器, 可以直接配置内部bean对象

                          

      通过内部bean, 设置属性

      public class SpringBeanTest {    @Test    public void setBeanByPro() {        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");        MemberServiceImpl memberService2 = ioc.getBean("memberService2", MemberServiceImpl.class);        memberService2.add();    }}

      对集合数组属性进行配置

      引用/注入 集合/数据类型

      1. 主要掌握List / Map / Properties 三种集合的使用
      2. Properties是Hashtable的子类, 是key-value的形式
      3. 这里的properties的k-v, 都是String类型

      在spring的ioc容器中, 如何给bean对象的 集合/数组 类型的属性赋值

      public class Master {    private String name;//主人名字    private List monsterList;    private Map monsterMap;    private Set monsterSet;    //数组    private String[] monsterName;    //Java基础    //这个Properties 是HashMap的子类, 是key-value的存放形式    //这里Properties key和value 都是String    private Properties properties;//getter, setter方法}

      给集合/数组属性进行赋值

      public class SpringBeanTest {    @Test    public void setBeanByCollection() {        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");        Master master = ioc.getBean("master", Master.class);        System.out.println("master=" + master);    }}

      对List属性进行配置

                                                                                                  

      对Map属性进行配置

                                                                          monster04                                                                                                            monster03                                                                        

      对Set属性进行配置

                                                                                                  

      对Array属性进行配置

                                      六耳猕猴            东海龙王            红孩儿            

      对Properties属性进行配置

                                      root            123456            978964140@qq.com            

      使用utillist进行配置

      spring的ioc容器, 可以通过util名称空间来创建list集合

      public class BookStore {    //书    private List bookList;    //无参构造器, 如果没有其它的构造器, 该无参构造器可以不写    //如果有其它的构造器, 则必须显示地定义一下无参构造器    public BookStore() {    }//getter, setter方法}

      beans.xml

          三体    时间简史    梦的解析    福尔摩斯探案集    

      使用util:list名称空间给属性赋值

      public class SpringBeanTest {    @Test    public void setBeanByUtilList() {        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");        BookStore bookStore = ioc.getBean("bookStore", BookStore.class);        System.out.println("bookStore=" + bookStore);    }}

      属性级联赋值配置

      spring的ioc容器, 可以直接给对象属性的属性赋值, 即级联属性赋值

      部门

      public class Dept {    private String name;    public Dept() {    }//getter, setter方法

      员工

      public class Employee {    private String name;    private Dept dept;    public Employee() {    }//getter, setter方法}

      beans.xml

                      

      给属性进行级联赋值

      public class SpringBeanTest {    @Test    public void setBeanByRelation() {        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");        Employee employee = ioc.getBean("employee", Employee.class);        System.out.println("employee=" + employee);    }}

      通过静态工厂获取bean

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

      这是一个静态工厂类-可以返回Monster对象

      package com.zzw.spring.factory;public class MyStaticFactory {    private static Map monsterMap;    //使用static代码块进行初始化 - java基础    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);    }}
          

      通过静态工厂获取bean

      public class SpringBeanTest {    @Test    public void getBeanByStaticFactory() {        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");        Monster myMonster01 = ioc.getBean("myMonster01", Monster.class);        Monster myMonster02 = ioc.getBean("myMonster01", Monster.class);        System.out.println("myMonster01=" + myMonster01);        System.out.println(myMonster01 == myMonster02);//true. myMonster01和myMonster02是同一个对象    }}

      bean配置信息重用

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

       

      通过继承, 配置bean

      public class SpringBeanTest {    @Test    public void getBeanByExtends() {        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");                Monster monster11 = ioc.getBean("monster11", Monster.class);        System.out.println("monster11=" + monster11);        Monster monster13 = ioc.getBean("monster13", Monster.class);        System.out.println("monster13=" + monster13);    }}

      bean创建顺序

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

      测试bean创建顺序

      实验1

       
      public class SpringBeanTest {    @Test    public void testBeanCreateOrder() {        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");        System.out.println("ok~");    }}
      public class Department {    public Department() {        System.out.println("Department构造器 被执行");    }}
      public class Student {    public Student() {        System.out.println("Student构造器 被执行");    }}

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

      运行结果

      Student构造器 被执行Department构造器 被执行ok~

      ※如果这样配置, 会先创建department01对象, 再创建student01对象

       

      运行结果

      Department构造器 被执行Student构造器 被执行ok~

      实验2

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

          

      答案:

      1)先创建 id=memberDao

      2)再创建 id=memberService

      3)调用 memberService.setMemberDao() 完成引用


      运行结果:

      MemberDaoImpl 构造器...MemberServiceImpl 构造器被执行setMemberDao()...

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

          

      答案:

      1)先创建 id=memberService

      2)再创建 id=memberDao

      3)调用 memberService.setMemberDao() 完成引用


      运行结果

      MemberServiceImpl 构造器被执行MemberDaoImpl 构造器...setMemberDao()...

      bean的单例和多实例

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

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

      public class Cat {    private Integer id;    private String name;        public Cat() {    //getter, setter方法}
              

      测试Scope

      @Testpublic 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);}

      使用细节

      1)bean默认是单例singleton; 在启动容器时, bean默认就会创建, 并放入到singletonObjects

      2) 当设置为多实例机制后, 该bean是在getBean()时被创建

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

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

      5) 如果scope=“prototype”, 这时你的lazy-init 属性的值不管是true还是false, 都是在getBean的时候才创建这个对象

      bean的生命周期

      bean对象创建是由JVM完成的, 然后执行如下方法

      1. 执行构造器
      2. 执行set相关方法
      3. 调用bean的初始化方法(需要配置)
      4. 使用bean
      5. 当容器关闭的时候, 调用bean的销毁方法(需要配置)

      ●代码实现

      1.新建com.zzw.spring.bean.House

      public class House {    private String name;    public House() {        System.out.println("House构造器 被执行...");    }    public void setName(String name) {        System.out.println("House setName()=" + name);        this.name = name;    }    //解读    //1.这个方法是由程序员来编写的    //2.根据自己的业务逻辑来写.    //3.名字也不是固定的    public void init() {        System.out.println("House init()....");    }    //解读    //1.这个方法是由程序员来编写的    //2.根据自己的业务逻辑来写.    //3.名字也不是固定的    public void destroy() {        System.out.println("House destroy()...");    }    @Override    public String toString() {        return "House{" +                "name='" + name + '\'' +                '}';    }}

      2.配置src/beans.xml

          

      3.测试bean的生命周期com.zzw.spring.test.SpringBeanTest

      public class SpringBeanTest {    @Test    public void testBeanLife() {        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");        House house = ioc.getBean("house", House.class);        System.out.println("house=" + house);        //关闭容器        //1.ioc的编译类型 ApplicationContext, 运行类型 ClassPathXmlApplicationContext        //2.因为ClassPathXmlApplicationContext 实现了 ConfigurableApplicationContext        //3.ClassPathXmlApplicationContext 是有close()的        //4.将ioc 转成ClassPathXmlApplicationContext, 再调用close()        //ioc.close()        //5.关闭ioc容器        ((ClassPathXmlApplicationContext) ioc).close();    }}

      4.输出

      House构造器 被执行...House setName()=上海豪宅House init()....setMemberDao()...house=com.zzw.spring.bean.House@327bcebdHouse destroy()...

      使用细节

      1.初始化-init方法和destroy方法, 由程序员来指定

      2.销毁方法就是当关闭容器时, 才会被调用

      配置bean后置处理器

      1在spring的ioc容器, 可以配置bean的后置处理器

      2.该 处理器/对象 会在bean初始化方法调用前和初始化方法调用后被调用

      3.bean中没有声明初始化方法, 后置处理器依然会发生作用

      4.程序员可以在后置处理器中编写自己的代码

      ●代码实现

      1.新建com.zzw.spring.bean.MyBeanPostProcessor

      //ctrl+h 可以查看类的继承关系//这是一个后置处理器, 需要实现 BeanPostProcessor接口public class MyBeanPostProcessor implements BeanPostProcessor {    /**     * 什么时候被调用: 在Bean的init方法前被调用     * @param bean     传入在ioc容器中 创建/配置 的bean     * @param beanName 传入在ioc容器中 创建/配置 的bean的id     * @return Object 是程序员对传入的bean进行修改/处理[如果有需要的话], 返回     * @throws BeansException     */    @Override    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {        System.out.println("postProcessBeforeInitialization()... bean="                + bean + " beanName=" + beanName);        return bean;    }    /**     * 什么时候被调用: 在Bean的init方法后被调用     * @param bean     传入在ioc容器中 创建/配置 的bean     * @param beanName 传入在ioc容器中 创建/配置 的bean的id     * @return Object 是程序员对传入的bean进行修改/处理[如果有需要的话], 返回     * @throws BeansException     */    @Override    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {        System.out.println("postProcessAfterInitialization()... bean="                + bean + " beanName=" + beanName);        return bean;    }}

      2.新建src/beans02.xml配置文件

          

      3.测试com.zzw.spring.test.SpringBeanTest

      public class SpringBeanTest {    @Test    public void testBeanPostProcessor() {        ApplicationContext ioc =                new ClassPathXmlApplicationContext("beans02.xml");        House house = ioc.getBean("house", House.class);        System.out.println("使用house=" + house);        //关闭容器        //ioc不能调用子类的特有的成员        //因为在编译阶段, 能调用哪些成员, 是由编译类型来决定的        //ioc编译类型 ApplicationContext, 运行类型 ClassPathXmlApplicationContext        ((ClassPathXmlApplicationContext) ioc).close();//向下转型    }}

      其它说明

      1.怎么执行到这个方法? => 使用AOP(反射+动态代理+IO+容器+注解)

      2.有什么用? => 可以对IOC容器中所有的对象进行统一处理, 比如日志处理/权限校验/安全验证/事务管理.

      -初步体验案例: 如果类型是House的统一改成 上海豪宅

      3.针对容器的所有对象吗? 是的=>切面编程

      4.后面我们会自己实现这个底层机制

      5.这是一个比较难以理解的知识点.

      1.修改src/beans02.xml

              

      2.修改com.zzw.spring.bean.MyBeanPostProcessor

      public class MyBeanPostProcessor implements BeanPostProcessor {    @Override    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {        System.out.println("postProcessBeforeInitialization()... bean="                + bean + " beanName=" + beanName);        //对多个对象进行处理/编程=>切面编程        if (bean instanceof House) {            ((House) bean).setName("上海豪宅~");        }        //这里返回一个空值并不会有任何影响        //return null;        return bean;    }        @Override    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {        System.out.println("postProcessAfterInitialization()... bean="                + bean + " beanName=" + beanName);        return bean;    }}

      3.测试com.zzw.spring.test.SpringBeanTest

      public class SpringBeanTest {    @Test    public void testBeanPostProcessor() {        ApplicationContext ioc =                new ClassPathXmlApplicationContext("beans02.xml");        House house = ioc.getBean("house", House.class);        House house02 = ioc.getBean("house02", House.class);        System.out.println("使用house=" + house);        System.out.println("使用house=" + house02);        //关闭容器        //ioc不能调用子类的特有的成员        //因为在编译阶段, 能调用哪些成员, 是由编译类型来决定的        //ioc编译类型 ApplicationContext, 运行类型 ClassPathXmlApplicationContext        ((ClassPathXmlApplicationContext) ioc).close();//向下转型    }}

      4.测试结果(return bean和return null都是下面的输出结果), 这是由底层机制决定的

      House构造器 被执行...House setName()=大豪宅postProcessBeforeInitialization()... bean=House{name='大豪宅'} beanName=houseHouse setName()=上海豪宅~House init()....postProcessAfterInitialization()... bean=House{name='上海豪宅~'} beanName=houseHouse构造器 被执行...House setName()=宫殿postProcessBeforeInitialization()... bean=House{name='宫殿'} beanName=house02House setName()=上海豪宅~House init()....postProcessAfterInitialization()... bean=House{name='上海豪宅~'} beanName=house02使用house=House{name='上海豪宅~'}使用house=House{name='上海豪宅~'}House destroy()...House destroy()...

      通过属性文件配置bean

      在spring的ioc容器, 通过属性文件给bean注入值

      在src目录下, 新建配置文件my.properties [配置文件都要写在src目录下]

      monsterId=1000name=\u5343\u5e74\u9f9f skill=\u65cb\u8f6c\u6253\u51fb

      解决中文乱码问题

                  
      public class SpringBeanTest {    //通过属性文件给bean属性赋值    @Test    public void setBeanByFile() {        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans03.xml");        Monster monster100 = ioc.getBean("monster100", Monster.class);        System.out.println("monster100=" + monster100);    }}

      基于XML的bean的自动装配

      在spring的ioc容器, 可以实现自动装配bean

      这里说的Action就是我们前面学习过的Servlet -> 充当Controller

      Dao

      package com.zzw.spring.dao;public class OrderDao { //DAO类    public void saveOrder() {        System.out.println("保存一个订单....");    }}

      Service

      package com.zzw.spring.service;public class OrderService { //Service类    //OrderDao属性    private OrderDao orderDao;    //getter方法    public OrderDao getOrderDao() {        return orderDao;    }    //setter方法    public void setOrderDao(OrderDao orderDao) {        this.orderDao = orderDao;    }}

      Action

      package com.zzw.spring.web;public class OrderAction { //Servlet就是Controller    //OrderService属性    private OrderService orderService;        //getter方法    public OrderService getOrderService() {        return orderService;    }        //setter方法    public void setOrderService(OrderService orderService) {        this.orderService = orderService;    }}

      bean03.xml

           

      通过自动装配来对属性赋值

      //通过自动装配来对属性赋值public class SpringBeanTest {    @Test    public void setBeanByAutowire() {        ApplicationContext ioc =                new ClassPathXmlApplicationContext("beans03.xml");        OrderAction orderAction = ioc.getBean("orderAction", OrderAction.class);        //验证是否自动装配上OrderService        System.out.println(orderAction.getOrderService());        //验证是否自动装配上OrderDao        System.out.println(orderAction.getOrderService().getOrderDao());    }}

      byName方式讲解

           

      Spring El 表达式配置Bean

      1.Spring Expression Language, Spring表达式语言, 简称SpEL. 支持运行时查询并可以操作对象.

      2.和EL表达式一样, SpEL根据JavaBean风格的getXxx(), setXxx()方法定义的属性访问对象

      3.SpEL使用#{…}作为界定符, 所有在大括号中的字符都被认为是SpEL表达式

      4.不是重点, 能看懂即可.

      public class SpELBean {    private String name;    private Monster monster;    private String monsterName;    private String crySound;    private String bookName;    private Double reuslt;    public SpELBean() {    }        //普通方法, 返回字符串    public String cry(String crySound) {        return "发出 " + " 的声音";    }    //静态方法 返回字符串    public static String read(String bookName) {        return "正在读" + bookName;    }//getter方法, setter方法    @Override    public String toString() {        return "SpELBean{" +                "name='" + name + '\'' +                "\nmonster=" + monster +                "\nmonsterName='" + monsterName + '\'' +                "\ncrySound='" + crySound + '\'' +                "\nbookName='" + bookName + '\'' +                "\nreuslt=" + reuslt +                '}';    }}

      beans04.xml

                                                      
      //通过spring el 对属性赋值public class SpringBeanTest {    @Test    public void setBeanBySpEl() {        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans04.xml");        SpELBean spELBean = ioc.getBean("spELBean", SpELBean.class);        System.out.println("spELBean=" + spELBean);    }}

      测试结果

      spELBean=SpELBean{name='赵志伟'monster=Monster{monsterId='1', name='齐天大圣', skill='金箍棒'}monsterName='齐天大圣'crySound='发出 小猫 的声音'bookName='正在读安乐传'reuslt=1863.3999999999999}

      下乘: Spring系列三:基于注解配置bean

上一篇:点歌机歌曲下载指南

下一篇:服务器怎么防护文件丢失?