基于XML配置bean
- 💖配置bean后置处理器
- 💖通过属性文件配置bean
- 💖基于XML的bean的自动装配
- 💖Spring El 表达式配置Bean
💖配置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
配置文件
<!--配置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 bean
和return 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