Spring-IOC—基于XML配置Bean
Spring-IOC—基于XML配置Bean
1.Spring 配置/管理 bean 介绍
1.Bean 管理包括两方面
1.创建bean对象
2.给bean注入属性
2.Bean配置方式
1.基于xml文件配置方式
2.基于注解方式
2.基于XML配置bean
1.通过类型来获取bean
1.应用案例
<!--2.通过类型获取bean-->
<bean class="com.llp.spring.bean.Monster">
<property name="monsterId" value="3"/>
<property name="name" value="琪琪"/>
<property name="skill" value="魅惑"/>
</bean>
@Test
public void getBeanByType(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
//通过类型获取bean,要求 ioc 容器中的同一个类的 bean 只能有一个!!
Monster bean = ioc.getBean(Monster.class);
System.out.println(bean);
}
2.使用细节
1、按类型来获取 bean, 要求 ioc 容器中的同一个类的 bean 只能有一个, 否则会抛出异常
org.springframework.beans.NotWritablePropertyException: Invalid property 'skill' of bean class [com.llp.spring.bean.Monster]: Bean property 'skill' is not writable or has an invalid setter method.
2、这种方式的应用场景:比如 XxxAction/Servlet/Controller, 或 XxxService 在一个线程
3、在容器配置文件(比如 beans.xml)中给属性赋值, 底层是通过setter 方法完成的, 这也是为什么我们需要提供 setter 方法的原因
2.通过构造器配置bean
1.应用案例
beans.xml
<!--3.通过构造器配置bean-->
<!--
1. constructor-arg标签可以指定使用构造器的参数
2. index表示构造器的第几个参数 从0开始计算的
3. 除了可以通过index 还可以通过 name / type 来指定参数方式
4. 类的构造器,不能有完全相同类型和顺序的构造器,所以可以通过type来指定
-->
<!--index方式-->
<bean class="com.llp.spring.bean.Monster" id="monster03">
<constructor-arg value="4" index="0"/>
<constructor-arg value="白骨精" index="1"/>
<constructor-arg value="吸血" index="2"/>
</bean>
<!--name方式-->
<bean class="com.llp.spring.bean.Monster" id="monster04">
<constructor-arg value="5" name="monsterId"/>
<constructor-arg value="蜘蛛精" name="name"/>
<constructor-arg value="吸血" name="skill"/>
</bean>
<!--type方式-->
<!--为什么可以? 类的构造器,不能有完全相同类型和顺序的构造器,所以可以通过type来指定-->
<bean class="com.llp.spring.bean.Monster" id="monster05">
<constructor-arg value="6" type="java.lang.Integer"/>
<constructor-arg value="黑熊精" type="java.lang.String"/>
<constructor-arg value="掏心" type="java.lang.String"/>
</bean>
@Test
public void getBeanByConstructor(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster monster03 = ioc.getBean("monster03",Monster.class);
System.out.println(monster03);
Monster monster04 = ioc.getBean("monster04",Monster.class);
System.out.println(monster04);
Monster monster05 = ioc.getBean("monster05",Monster.class);
System.out.println(monster05);
}
2.使用细节
- 通过 index 属性来区分是第几个参数
- 通过 type 属性来区分是什么类型(按照顺序)
3.通过p名称空间配置bean
1.应用案例
<!--通过 p 名称空间配置 bean-->
<bean class="com.llp.spring.bean.Monster" id="monster06"
p:monsterId="6"
p:name="红孩儿"
p:skill="三味真火"
/>
@Test
public void getBeanByPNameSpace(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster bean = ioc.getBean("monster06",Monster.class);
System.out.println(bean);
}
4.引用/注入其他bean对象
1.应用案例
beans.xml
<!--1. ref="memberDAO"表示 MemberServiceImpl对象属性memberDAO引用的对象是id=memberDAO的对象
2. 这里就体现出spring容器的依赖注入
3. 注意再spring容器中, 他是作为一个整体来执行的, 即如果你引用到一个bean对象, 对你配置的顺序没有要求
4. 建议还是按顺序,好处是阅读的时候,比较方便-->
<bean class="com.llp.spring.service.MemberServiceImpl" id="memberService" p:memberDao-ref="memberDao">
<!--<property name="memberDao" ref="memberDao"/>-->
</bean>
<!--引用/注入其他bean对象
注意这里的memberDao和MemberServiceImpl配置中的ref一致-->
<bean class="com.llp.spring.dao.MemberDaoImpl" id="memberDao"/>
//通过ref来设置bean属性
@Test
public void setBeanByRef(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
MemberServiceImpl memberService = ioc.getBean("memberService", MemberServiceImpl.class);
memberService.add();
}
5.引入/注入内部bean对象
1.应用案例
<!--引用/注入其他bean对象-->
<bean class="com.llp.spring.dao.MemberDaoImpl" id="memberDao"/>
<!--配置MemberServiceImpl对象,使用内部bean的方式-->
<bean class="com.llp.spring.service.MemberServiceImpl" id="memberService2">
<!--MemberServiceImpl对象中有一个属性memberDao,
自己配置一个内部的bean-->
<property name="memberDao">
<bean class="com.llp.spring.dao.MemberDaoImpl"/>
</property>
</bean>
/**
* 通过内部bean设置属性
*/
@Test
public void setBeanByPro(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
MemberServiceImpl memberService = ioc.getBean("memberService2", MemberServiceImpl.class);
memberService.add();
}
6.引入/注入集合/数组类型
1.应用案例
Master.java实体类
public class Master {
private String name;//主人名
private List<Monster> monsterList;
private Map<String, Monster> monsterMap;
private Set<Monster> monsterSet;
//数组
private String[] monsterName;
//Java基础
//这个Properties 是 Hashtable的子类 , 是key-value的形式
//这里Properties key和value 都是String
private Properties pros;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Monster> getMonsterList() {
return monsterList;
}
public void setMonsterList(List<Monster> monsterList) {
this.monsterList = monsterList;
}
public Map<String, Monster> getMonsterMap() {
return monsterMap;
}
public void setMonsterMap(Map<String, Monster> monsterMap) {
this.monsterMap = monsterMap;
}
public Set<Monster> getMonsterSet() {
return monsterSet;
}
public void setMonsterSet(Set<Monster> monsterSet) {
this.monsterSet = monsterSet;
}
public String[] getMonsterName() {
return monsterName;
}
public void setMonsterName(String[] monsterName) {
this.monsterName = monsterName;
}
public Properties getPros() {
return pros;
}
public void setPros(Properties pros) {
this.pros = pros;
}
@Override
public String toString() {
return "Master{" +
"name='" + name + '\'' +
", monsterList=" + monsterList +
", monsterMap=" + monsterMap +
", monsterSet=" + monsterSet +
", monsterName=" + Arrays.toString(monsterName) +
", pros=" + pros +
'}';
}
}
<!--配置Master对象
体会 spring 容器配置特点 依赖注入-非常灵活
-->
<bean class="com.llp.spring.bean.Master" id="master">
<property name="name" value="太上老君"/>
<!--给list属性赋值-->
<property name="monsterList">
<list>
<!--引用的方法-->
<ref bean="monster01"/>
<ref bean="monster02"/>
<!--内部bean-->
<bean class="com.llp.spring.bean.Monster">
<property name="name" value="老鼠精"/>
<property name="monsterId" value="100"/>
<property name="skill" value="吃粮食"/>
</bean>
</list>
</property>
<!--给map属性赋值-->
<property name="monsterMap">
<map>
<entry>
<key>
<value>monster03</value>
</key>
<!--这里使用的外部bean,引入-->
<ref bean="monster03"/>
</entry>
<entry>
<key>
<value>monster04</value>
</key>
<ref bean="monster04"/>
</entry>
</map>
</property>
<!--给set属性赋值-->
<property name="monsterSet">
<set>
<ref bean="monster05"/>
<ref bean="monster06"/>
<bean class="com.llp.spring.bean.Monster">
<property name="name" value="金角大王"/>
<property name="skill" value="吐水"/>
<property name="monsterId" value="666"/>
</bean>
</set>
</property>
<!--给数组属性赋值
array标签中使用 value 还是 bean , ref .. 要根据你的业务决定
-->
<property name="monsterName">
<array>
<value>小妖怪</value>
<value>大妖怪</value>
<value>老妖怪</value>
</array>
</property>
<!--给Properties属性赋值 结构k(String)-v(String)-->
<property name="pros">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
<prop key="ip">127.0.0.1</prop>
</props>
</property>
</bean>
2.使用细节
-
主要掌握 List/Map/Properties 三种集合的使用.
-
Properties 集合的特点
1)这个 Properties 是 Hashtable 的子类 , 是 key-value 的形式
2)key 是 string 而 value 也是 string
7.通过util名称空间创建list
1.应用案例
xmlns:util="http://www.springframework.org/schema/util"
beans.xml
<util:list id="bookList">
<value>三国演义</value>
<value>被讨厌的勇气</value>
<value>西游记</value>
<value>三字经</value>
</util:list>
<!--通过util名称空间创建list-->
<bean class="com.llp.spring.bean.BookStore" id="bookStore">
<property name="bookList" ref="bookList"/>
</bean>
BookStore.java
public class BookStore {
private List<String> bookList;
public List<String> getBookList() {
return bookList;
}
public void setBookList(List<String> bookList) {
this.bookList = bookList;
}
@Override
public String toString() {
return "BookStore{" +
"bookList=" + bookList +
'}';
}
}
测试
@Test
public void getBeanByUtilList(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
BookStore bean = ioc.getBean("bookStore",BookStore.class);
System.out.println(bean);
}
8.级联属性赋值
1.应用案例
<!--级联属性赋值-->
<bean class="com.llp.spring.bean.Emp" id="emp">
<property name="name" value="小红"/>
<property name="dept" ref="dept"/>
<property name="dept.name" value="后勤"/>
</bean>
<bean class="com.llp.spring.bean.Dept" id="dept"/>
/**
* 级联属性赋值
*/
@Test
public void getBeanByRelation(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Emp bean = ioc.getBean("emp", Emp.class);
System.out.println(bean);
}
9.通过静态工厂获取对象
1.应用案例
<!--配置monster对象,通过静态工厂获取
1. 通过静态工厂获取/配置bean
2. class 是静态工厂类的全路径
3. factory-method 表示是指定静态工厂类的哪个方法返回对象
4. constructor-arg value="monster02" value是指定要返回静态工厂的哪个对象-->
<bean id="my_monster01" class="com.llp.spring.factory.MyStaticFactory" factory-method="getBean">
<!--注意这里的value,通过value从map中获取monster对象 ==>MyStaticFactory.getBean(monsterMap.get(monster02))-->
<constructor-arg value="monster02"/>
</bean>
MyStaticFactory工厂类
/**
* 可以创建返回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 getBean(String key){
return monsterMap.get(key);
}
}
测试类
@Test
public void getBeanByStaticFactory(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster bean = ioc.getBean("my_monster01", Monster.class);
System.out.println(bean);
}
测试结果
10.通过实例工厂获取对象
1.应用案例
beans.xml
<!--配置一个实例工厂对象-->
<bean class="com.llp.spring.factory.MyInstanceFactory" id="instanceFactory"/>
<!--配置monster对象,通过实例工厂
1. factory-bean 指定使用哪个实例工厂对象返回bean
2. factory-method 指定使用实例工厂对象的哪个方法返回bean
3. constructor-arg value="monster03" 指定获取到实例工厂中的哪个monster
-->
<bean id="my_monster02" factory-bean="instanceFactory" factory-method="getMonster">
<!--创建MyInstanceFactory工厂类
1.MyInstanceFactory instanceFactory = new MyInstanceFactory();
通过value传入getMonster中获取Monster对象
2.instanceFactory.getMonster(monster_Map.get(monster03));
-->
<constructor-arg value="monster03"/>
</bean>
实例工厂类
public class MyInstanceFactory {
private static Map<String, Monster> monster_Map;
{
monster_Map = new HashMap<>();
monster_Map.put("monster03",new Monster(300,"孙悟空","耍光棍"));
monster_Map.put("monster04",new Monster(400,"蜘蛛精","盘丝"));
}
public Monster getMonster(String key){
return monster_Map.get(key);
}
}
测试类
@Test
public void getBeanByInstanceFactory(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster bean01 = ioc.getBean("my_monster02", Monster.class);
Monster bean02 = ioc.getBean("my_monster02", Monster.class);
System.out.println(bean01);
/**
* 这里调用my_monster02 都是调用已经创建好的MyInstanceFactory对象的getMonster方法
* 注意的是,MyInstanceFactory是单独配置的并不会创建两次
*/
System.out.println(bean01 == bean02);//true
}
测试结果
11.通过FactoryBean获取对象(重点)
1.应用案例
FactoryBean
/**
* 一个FactoryBean
*/
public class MyFactoryBean implements FactoryBean<Monster> {
//这个就是你配置时候,指定要获取的对象对应key
private String key;
private Map<String, Monster> monster_map;
{ //代码块,完成初始化
monster_map = new HashMap<>();
monster_map.put("monster03", new Monster(300, "牛魔王~", "芭蕉扇~"));
monster_map.put("monster04", new Monster(400, "狐狸精~", "美人计~"));
}
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表示就是 MyFactoryBean 属性key
3. value就是你要获取的对象对应key
-->
<bean id="my_monster03" class="com.llp.spring.factory.MyFactoryBean">
<!--
MyFactoryBean myFactoryBean = new MyFactoryBean();
myFactoryBean.setKey(monster_map.get(monster04))
-->
<property name="key" value="monster04"/>
</bean>
测试类
@Test
public void getBeanByFactoryBean(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster my_monster03 = ioc.getBean("my_monster03", Monster.class);
System.out.println(my_monster03);
}
测试结果
12.bean配置信息重用(继承)
1.应用案例
beans.xml
<!--配置Monster对象-->
<bean id="monster10" class="com.llp.spring.bean.Monster">
<property name="monsterId" value="10"/>
<property name="name" value="蜈蚣精"/>
<property name="skill" value="蜇人"/></bean>
<!--
1.配置Monster对象
2.但是这个对象的属性值和id=monster10的对象属性一致
3.parent="monster10"表示指定当前配置对象的属性值从id=monster10的对象获取
-->
<bean id="monster11" class="com.llp.spring.bean.Monster" parent="monster10"/>
测试类
/**
* 配置bean通过继承(extends)
*/
@Test
public void getBeanByExtends(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster monster10 = ioc.getBean("monster10", Monster.class);
Monster monster11 = ioc.getBean("monster11", Monster.class);
System.out.println(monster10);
System.out.println(monster11);
//monster11对象的属性值继承至monster10,但monster11和monster10并不是同一个对象
System.out.println(monster10 == monster11);//false
}
测试结果
注意
<!--配置Monster对象
1.如果bean指定了abstract="true",表示该对象适用于被继承的
2.这个bean本身是不能被实例化的
3.这个bean的价值就是专门用来被继承的
-->
<bean id="monster12" class="com.llp.spring.bean.Monster" abstract="true">
<property name="monsterId" value="10"/>
<property name="name" value="蜈蚣精"/>
<property name="skill" value="蜇人"/>
</bean>
13.bean创建顺序
1.应用案例
beans.xml
<!--测试bean对象的创建顺序
1. 在默认情况下, bean创建的顺序是按照配置顺序来的(从上到下)
2. 但是如果我们增加了 depends-on="department01" 这时就会先创建id= department01对象
-->
<bean id="student01" class="com.llp.spring.bean.Student" depends-on="department01"/>
<bean id="department01" class="com.llp.spring.bean.Department"/>
测试类
@Test
public void getBeanByCreate(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Student student = ioc.getBean("student01", Student.class);
Department department = ioc.getBean("department01", Department.class);
}
测试结果
2.一个问题?
● 问题说明
- 先看下面的配置, 请问两个 bean 创建的顺序是什么? 并分析执行流程
1)先创建 id=memberDAOImpl
2)再创建 id = memberServiceImpl
3)调用 memberServiceImpl.setMemberDAO() 完成引用
- 先看下面的配置, 请问两个 bean 创建的顺序是什么, 并分析执行流程
1)先创建 id = memberServiceImpl
2)再创建 id=memberDAOImpl
3)用 memberServiceImpl.setMemberDAO() 完成引用
14.bean对象的单例和多例
1.应用案例
在 spring 的 ioc 容器, 在默认是按照单例创建的,即配置一个 bean 对象后,ioc 容器只会创建一个 bean 实例。
如果,我们希望 ioc 容器配置的某个 bean 对象,是以多个实例形式创建的则可以通过配置scope="prototype" 来指定
Cat.java
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;
}
//@Override
//public String toString() {
// return "Cat{" +
// "id=" + id +
// ", name='" + name + '\'' +
// '}';
//}
}
beans.xml
<!--配置Cat对象
1. 在默认情况下 scope属性是 singleton
2. 在ioc容器中, 只要有一个这个bean对象
3. 当程序员执行getBean时, 返回的的是同一个对象
4. 如果我们希望每次getBean返回一个新的Bean对象,则可以scope="prototype"
5. 如果bean的配置是 scope="singleton" lazy-init="true" 这时,ioc容器就不会提前创建该对象
, 而是当执行getBean方法的时候,才会创建对象
-->
<bean id="cat" class="com.llp.spring.bean.Cat" scope="prototype" lazy-init="false">
<property name="id" value="100"/>
<property name="name" value="小花猫"/>
</bean>
测试
@Test
public void getBeanByPrototype(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Cat cat01 = ioc.getBean("cat", Cat.class);
Cat cat02 = ioc.getBean("cat", Cat.class);
System.out.println(cat01);
System.out.println(cat02);
//false
System.out.println(cat01==cat02);
}
测试结果
2.使用细节
- 默认是单例singleton, 在启动容器时, 默认就会创建 , 并放入到singletonObjects集合
- 当 < bean scope="prototype" > 设置为多实例机制后, 该 bean 是在 getBean()时才创建
- 如 果 是 单 例 singleton, 同 时 希 望 在 getBean 时 才 创 建 , 可 以 指 定 懒 加 载 lazy-init="true" (注意默认是 false)
- 通常情况下, lazy-init 就使用默认值 false , 在开发看来, 用空间换时间是值得的, 除非有特殊的要求.
- 如果 scope="prototype" 这时你的 lazy-init 属性的值不管是 ture, 还是 false 都是在getBean 时候才创建对象.
15.bean的生命周期
1.应用案例
● 说明: bean 对象创建是由 JVM 完成的,然后执行如下方法
- 执行构造器
- 执行 set 相关方法
- 调用 bean 的初始化的方法(需要配置)
- 使用 bean
- 当容器关闭时候,调用 bean 的销毁方法(需要配置)
House.java
public class House {
private String name;
public House() {
System.out.println("House() 构造器...");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("House setName()=" + name);
this.name = name;
}
//1. 这个方法是程序员来编写的.
//2. 根据自己的业务逻辑来写.
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 + '\'' +
'}';
}
}
beans.xml
<!--配置House对象,演示整个Bean的生命周期
1. init-method="init" 指定bean的初始化方法 , 在setter方法后执行
2. init方法执行的时机,有spring容器来控制
3. destroy-method="destroy" 指定bean的销毁方法, 在容器关闭的时候执行
4. destroy方法执行的时机,有spring容器来控制
-->
<bean id="house" class="com.llp.spring.bean.House" init-method="init" destroy-method="destroy" >
<property name="name" value="北京豪宅"/>
</bean>
测试
//测试Bean的生命周期
@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();
//关闭ioc容器.
((ConfigurableApplicationContext) ioc).close();
}
2.使用细节
- 初始化 init 方法和 destory 方法, 是程序员来指定
- 销毁方法就是当关闭容器时,才会被调用.
16.配置bean的后置处理器【比较难】
1.应用案例
● 说明
- 在 spring 的 ioc 容器,可以配置 bean 的后置处理器
- 该处理器/对象会在 bean 初始化方法调用前和初始化方法调用后被调用
- 程序员可以在后置处理器中编写自己的代码
● 应用实例演示
bean—House
public class House {
private String name;
public House() {
System.out.println("House() 构造器...");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("House setName()=" + name);
this.name = name;
}
//1. 这个方法是程序员来编写的.
//2. 根据自己的业务逻辑来写.
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 + '\'' +
'}';
}
}
beans2.xml
<!--配置house对象-->
<bean class="com.llp.spring.bean.House" id="house" init-method="init" destroy-method="destroy">
<property name="name" value="我的房子"/>
</bean>
<!--配置后置处理器对象
1. 当我们在beans02.xml 容器配置文件 配置了 MyBeanPostProcessor
2. 这时后置处理器对象,就会作用在该容器创建的Bean对象
3. 已经是针对所有对象编程->切面编程AOP
-->
<bean class="com.llp.spring.bean.MyBeanPostProcessor"/>
后置处理器
/**
* 后置处理器
*/
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 程序员对传入的bean 进行修改/处理【如果有需要的话】 ,返回
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization(),bean="+bean+",beanName="+beanName);
return bean;
}
}
@Test
public void testBeanPostProcessor(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans02.xml");
House house = ioc.getBean("house", House.class);
System.out.println(house);
}
2.其他说明
1、怎么执行到这个方法?=> 使用 AOP(反射+动态代理+IO+容器+注解)
2、有什么用?=> 可以对 IOC 容器中所有的对象进行统一处理 ,比如 日志处理/权限的校验
-初步体验案例: 如果类型是 House 的统一改成 上海豪宅
3、针对容器的所有对象吗? 是的=>切面编程特点
17.通过属性文件给 bean 注入值
1.应用实例
beans02.xml
<!--指定属性文件
location 表示指定属性文件的位置-->
<context:property-placeholder location="classpath:my.properties"/>
<!--配置Monster对象
1.通过属性文件给monster对象的属性赋值
2.这是我们的属性值通过${属性名}
3.这里说的属性名就是my.properties文件中的k=v的k-->
<bean class="com.llp.spring.bean.Monster" id="monster1000">
<property name="monsterId" value="${monsterId}"/>
<property name="name" value="${name}"/>
<property name="skill" value="${skill}"/>
</bean>
测试
@Test
public void setBeanByFile(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans02.xml");
Monster monster1000 = ioc.getBean("monster1000", Monster.class);
//Monster{monsterId=100, name='琪琪', skill='魅惑'}
System.out.println(monster1000);
}
18.基于XML的bean的自动装配
1.应用实例-byType
public class OrderDao {
public void saveOrder(){
System.out.println("保存 一个订单...");
}
}
public class OrderServiceImpl {
private OrderDao orderDao;
public OrderDao getOrderDao() {
return orderDao;
}
public void setOrderDao(OrderDao orderDao) {
this.orderDao = orderDao;
}
public void saveOrder(){
orderDao.saveOrder();
}
}
public class OrderAction {
private OrderServiceImpl orderService;
public OrderServiceImpl getOrderService() {
return orderService;
}
public void setOrderService(OrderServiceImpl orderService) {
this.orderService = orderService;
}
public void saveOrder(){
orderService.saveOrder();
}
}
<bean class="com.llp.spring.dao.OrderDao" id="orderDao"/>
<!--配置OrderService对象
1. autowire="byType" 表示 在创建 orderService时
通过类型的方式 给对象属性 自动完成赋值/引用
2. 比如OrderService 对象有 private OrderDao orderDao
3. 就会在容器中去找有没有 OrderDao类型对象
4. 如果有,就会自动的装配, 如果是按照 byType 方式来装配, 这个容器中,不能有两个
的OrderDao类型对象
5. 如果你的对象没有属性, autowire就没有必要写
6. 其它类推..
-->
<bean class="com.llp.spring.service.OrderServiceImpl" id="orderService" autowire="byType"/>
<bean class="com.llp.spring.web.OrderAction" id="orderAction" autowire="byType"/>
2.应用实例-byName
<bean class="com.llp.spring.dao.OrderDao" id="orderDao"/>
<!--配置OrderService对象
1. 如果我们设置的是 autowire="byName" 表示通过名字完成自动装配
2. 比如下面的 autowire="byName" class="com.llp.spring.service.OrderService"
1) 先看 OrderService 属性 private OrderDao orderDao
2) 再根据这个属性的setXxx()方法的 xxx 来找对象id
3) public void setOrderDao() 就会找id=orderDao对象来进行自动装配
4) 如果没有就装配失败
-->
<bean class="com.llp.spring.service.OrderServiceImpl" id="orderService" autowire="byName"/>
<bean class="com.llp.spring.web.OrderAction" id="orderAction" autowire="byName"/>
@Test
public void testAutowaireByName(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans03.xml");
OrderAction orderAction = ioc.getBean("orderAction", OrderAction.class);
System.out.println(orderAction.getOrderService());
System.out.println(orderAction.getOrderService().getOrderDao());
}
19.Sping el表达式
1.应用实例
● 说明
- Spring Expression Language,Spring 表达式语言,简称 SpEL。支持运行时查询并可以操作对象。
- 和 EL 表达式一样,SpEL 根据 JavaBean 风格的 getXxx()、setXxx()方法定义的属性访问对象
- SpEL 使用#{…}作为定界符,所有在大框号中的字符都将被认为是 SpEL 表达式。
public class SpELBean {
private String name;
private Monster monster;
private String monsterName;
private String crySound; //叫声
private String bookName;
private Double result;
public SpELBean() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Monster getMonster() {
return monster;
}
public void setMonster(Monster monster) {
this.monster = monster;
}
public String getMonsterName() {
return monsterName;
}
public void setMonsterName(String monsterName) {
this.monsterName = monsterName;
}
public String getCrySound() {
return crySound;
}
public void setCrySound(String crySound) {
this.crySound = crySound;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public Double getResult() {
return result;
}
public void setResult(Double result) {
this.result = result;
}
//cry 方法会返回字符串
public String cry(String sound) {
return "发出 " + sound + "叫声...";
}
//read 返回字符串
public static String read(String bookName) {
return "正在看 " + bookName;
}
@Override
public String toString() {
return "SpELBean{" +
"name='" + name + '\'' +
", monster=" + monster +
", monsterName='" + monsterName + '\'' +
", crySound='" + crySound + '\'' +
", bookName='" + bookName + '\'' +
", result=" + result +
'}';
}
}
<!--配置一个monster对象-->
<bean id="monster01" class="com.llp.spring.bean.Monster">
<property name="monsterId" value="100"/>
<property name="name" value="蜈蚣精~"/>
<property name="skill" value="蜇人~"/>
</bean>
<!-- spring el 表达式使用
1. 通过spel给bean的属性赋值
-->
<bean id="spELBean" class="com.llp.spring.bean.SpELBean">
<!-- sp el 给字面量 -->
<property name="name" value="#{'llp'}"/>
<!-- 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.llp.spring.bean.SpELBean).read('天龙八部')}"/>
<!-- sp el 通过运算赋值 -->
<property name="result" value="#{89*1.2}"/>
</bean>
//通过spring el 对属性赋值
@Test
public void setBeanBySpel() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans04.xml");
SpELBean spELBean = ioc.getBean("spELBean", SpELBean.class);
System.out.println("spELBean=" + spELBean);
}
测试结果