Spring系列二:基于XML配置bean 下

在这里插入图片描述

💖配置bean后置处理器

1在springioc容器, 可以配置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配置文件

<!--配置House对象-->
<bean class="com.zzw.spring.bean.House" id="house"
      init-method="init"
      destroy-method="destroy">
    <property name="name" value="大豪宅"/>
</bean>

<!--配置后置处理器对象
解读:
1.当我们在beans02.xml 容器配置文件, 配置了MyBeanPostProcessor
2.这时后置处理器对象, 就会作用在该容器创建的所有bean对象
-->
<bean class="com.zzw.spring.bean.MyBeanPostProcessor" id="beanPostProcessor"/>

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

<!--配置House对象-->
<bean class="com.zzw.spring.bean.House" id="house"
      init-method="init"
      destroy-method="destroy">
    <property name="name" value="大豪宅"/>
</bean>

<bean class="com.zzw.spring.bean.House" id="house02"
      init-method="init"
      destroy-method="destroy">
    <property name="name" value="宫殿"/>
</bean>

<!--配置后置处理器对象
解读:
1.当我们在beans02.xml 容器配置文件, 配置了MyBeanPostProcessor
2.这时后置处理器对象, 就会作用在该容器的创建的bean对象
3.已经是针对所有对象编程->切面编程AOP
-->
<bean class="com.zzw.spring.bean.MyBeanPostProcessor" id="beanPostProcessor"/>

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 beanreturn null都是下面的输出结果), 这是由底层机制决定的

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

💖通过属性文件配置bean

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

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

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

解决中文乱码问题
在这里插入图片描述

2.新建src/beans03.xml增加如下配置

<!--指定属性文件
说明
1.先把文件修改成提示All Problem, 在右上角
2.提示错误, 将光标放在context 输入alt+enter, 就会自动引入namespace
3.location="classpath:my.properties" 表示指定属性文件的位置
4.提示, 需要带上 classpath
-->
<context:property-placeholder location="classpath:my.properties"/>

<!--配置monster对象
1.通过属性文件给monster对象的属性赋值
2.这时我们的属性值, 通过${属性名}
3.这里说的 属性名, 就是 my.properties文件中的 k=v 的k
-->
<bean class="com.zzw.spring.bean.Monster" id="monster100">
    <property name="monsterId" value="${monsterId}"/>
    <property name="name" value="${name}"/>
    <property name="skill" value="${skill}"/>
</bean>

3.测试: com/zzw/spring/test/SpringBeanTest.java增加setBeanByFile方法

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

1.新建com.zzw.spring.dao.OrderDao

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

2.新建com.zzw.spring.service.OrderService

public class OrderService { //Service类

    //OrderDao属性
    private OrderDao orderDao;

    //getter方法
    public OrderDao getOrderDao() {
        return orderDao;
    }

    //setter方法
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }
}

3.新建com.zzw.spring.web.OrderAction

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

4.src/beans03.xml增加如下配置

<!--配置OrderDao对象-->
<bean class="com.zzw.spring.dao.OrderDao" id="orderDao"/>
<!--配置OrderService对象
解读:
1.autowire="byType" 表示 在创建orderService时,
  通过类型的方式给对象的属性 自动完成赋值/引用
2.比如OrderService对象有 private OrderDao orderDao
3.就会在容器中去找有没有 OrderDao类型对象
4.如果有, 就会自动地装配. 提示: 如果是按照 byType 方式来装配, 这个容器中不能有两个
  OrderDao类型的对象
5.如果你的对象没有属性, autowire就没有必要写
6.其它类推...
-->
<bean autowire="byType" class="com.zzw.spring.service.OrderService"
      id="orderService"/>
<!--配置OrderAction对象-->
<bean autowire="byType" class="com.zzw.spring.web.OrderAction" id="orderAction"/>

5.测试: com/zzw/spring/test/SpringBeanTest.java增加setBeanByAutowire方法

//通过自动装配来对属性赋值
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());
    }
}

6.byName方式讲解, src/beans03.xml增加如下配置

<!--
7.如果我们设置的是 autowire="byName" 表示通过名字完成自动装配
8.比如下面的 autowire="byName" class="com.zzw.spring.service.OrderService"
  1) 先看 OrderService 属性 private OrderDao orderDao;
  2) 再根据这个属性的setXxx()方法的 xxx 来找对象id
  3) public void setOrderDao() 就会找 id=orderDao对象来进行自动装配
  4) 如果没有就装配失败
-->
<bean autowire="byName" class="com.zzw.spring.service.OrderService"
      id="orderService"/>
<!--配置OrderAction对象-->
<bean autowire="byName" class="com.zzw.spring.web.OrderAction" id="orderAction"/>

7.测试…

💖Spring El 表达式配置Bean

1.Spring Expression Language, Spring表达式语言, 简称SpEL. 支持运行时查询并可以操作对象.
2.和EL表达式一样, SpEL根据JavaBean风格的getXxx(), setXxx()方法定义的属性访问对象
3.SpEL使用#{...}作为界定符, 所有在大括号中的字符都被认为是SpEL表达式
4.不是重点, 能看懂即可.

●代码实现
1.新建com.zzw.spring.bean.SpELBean

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方法, toString方法

2.src/beans04.xml增加如下配置

<!--配置一个monster对象-->
<bean class="com.zzw.spring.bean.Monster" id="monster01"
      p:monsterId="001"
      p:name="齐天大圣"
      p:skill="金箍棒"
/>

<!--spring el 表达式使用
解读
1.通过spEl给bean的属性赋值
-->
<bean class="com.zzw.spring.bean.SpELBean" id="spELBean">
    <!--sp el 给字面量-->
    <property name="name" value="#{'赵志伟'}"/>
    <!--sp el 引用其它bean-->
    <property name="monster" value="#{monster01}"/>
    <!--sp el 引用其它bean的属性值-->
    <property name="monsterName" value="#{monster01.name}"/>
    <!--sp el 调用普通方法(返回值) 赋值-->
    <property name="crySound" value="#{spELBean.cry('小猫')}"/>
    <!--sp el 调用静态方法(返回值) 赋值-->
    <property name="bookName" value="#{T(com.zzw.spring.bean.SpELBean).read('安乐传')}"/>
    <!--sp el 通过运算赋值-->
    <property name="reuslt" value="#{72+53*33.8}"/>
</bean>

3.测试: com/zzw/spring/test/SpringBeanTest.java增加setBeanBySpEl方法

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

4.测试结果

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

下一章节: Spring系列三:基于注解配置bean

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~ 小团子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值