Spring-IOC—基于XML配置Bean
1.Spring 配置/管理 bean 介绍
1.Bean 管理包括两方面
1.创建bean对象
2.给bean注入属性
2.Bean配置方式
1.基于xml文件配置方式
2.基于注解方式
2.基于XML配置bean
1.通过类型来获取bean
1.应用案例
<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");
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
<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>
<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>
<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.应用案例
<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
<bean class="com.llp.spring.service.MemberServiceImpl" id="memberService" p:memberDao-ref="memberDao">
</bean>
<bean class="com.llp.spring.dao.MemberDaoImpl" id="memberDao"/>
@Test
public void setBeanByRef(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
MemberServiceImpl memberService = ioc.getBean("memberService", MemberServiceImpl.class);
memberService.add();
}
5.引入/注入内部bean对象
1.应用案例
<bean class="com.llp.spring.dao.MemberDaoImpl" id="memberDao"/>
<bean class="com.llp.spring.service.MemberServiceImpl" id="memberService2">
<property name="memberDao">
<bean class="com.llp.spring.dao.MemberDaoImpl"/>
</property>
</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;
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 +
'}';
}
}
<bean class="com.llp.spring.bean.Master" id="master">
<property name="name" value="太上老君"/>
<property name="monsterList">
<list>
<ref bean="monster01"/>
<ref bean="monster02"/>
<bean class="com.llp.spring.bean.Monster">
<property name="name" value="老鼠精"/>
<property name="monsterId" value="100"/>
<property name="skill" value="吃粮食"/>
</bean>
</list>
</property>
<property name="monsterMap">
<map>
<entry>
<key>
<value>monster03</value>
</key>
<ref bean="monster03"/>
</entry>
<entry>
<key>
<value>monster04</value>
</key>
<ref bean="monster04"/>
</entry>
</map>
</property>
<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>
<property name="monsterName">
<array>
<value>小妖怪</value>
<value>大妖怪</value>
<value>老妖怪</value>
</array>
</property>
<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>
<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.应用案例
<bean id="my_monster01" class="com.llp.spring.factory.MyStaticFactory" factory-method="getBean">
<constructor-arg value="monster02"/>
</bean>
MyStaticFactory工厂类
public class MyStaticFactory {
private static Map<String, Monster> monsterMap;
static{
monsterMap = new HashMap<>();
monsterMap.put("monster01",new Monster(100,"阿牛","芭蕉扇"));
monsterMap.put("monster02",new Monster(200,"狐狸精","美人计"));
}
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"/>
<bean id="my_monster02" factory-bean="instanceFactory" factory-method="getMonster">
<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);
System.out.println(bean01 == bean02);
}
测试结果
11.通过FactoryBean获取对象(重点)
1.应用案例
FactoryBean
public class MyFactoryBean implements FactoryBean<Monster> {
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
<bean id="my_monster03" class="com.llp.spring.factory.MyFactoryBean">
<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
<bean id="monster10" class="com.llp.spring.bean.Monster">
<property name="monsterId" value="10"/>
<property name="name" value="蜈蚣精"/>
<property name="skill" value="蜇人"/></bean>
<bean id="monster11" class="com.llp.spring.bean.Monster" parent="monster10"/>
测试类
@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);
System.out.println(monster10 == monster11);
}
测试结果
注意
<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 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;
}
}
beans.xml
<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);
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;
}
public void init() {
System.out.println("House init()..");
}
public void destroy() {
System.out.println("House destroy()..");
}
@Override
public String toString() {
return "House{" +
"name='" + name + '\'' +
'}';
}
}
beans.xml
<bean id="house" class="com.llp.spring.bean.House" init-method="init" destroy-method="destroy" >
<property name="name" value="北京豪宅"/>
</bean>
测试
@Test
public void testBeanLife() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
House house = ioc.getBean("house", House.class);
System.out.println("使用house=" + house);
((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;
}
public void init() {
System.out.println("House init()..");
}
public void destroy() {
System.out.println("House destroy()..");
}
@Override
public String toString() {
return "House{" +
"name='" + name + '\'' +
'}';
}
}
beans2.xml
<bean class="com.llp.spring.bean.House" id="house" init-method="init" destroy-method="destroy">
<property name="name" value="我的房子"/>
</bean>
<bean class="com.llp.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);
return bean;
}
@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);
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"/>
<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"/>
<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;
}
public String cry(String sound) {
return "发出 " + sound + "叫声...";
}
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 +
'}';
}
}
<bean id="monster01" class="com.llp.spring.bean.Monster">
<property name="monsterId" value="100"/>
<property name="name" value="蜈蚣精~"/>
<property name="skill" value="蜇人~"/>
</bean>
<bean id="spELBean" class="com.llp.spring.bean.SpELBean">
<property name="name" value="#{'llp'}"/>
<property name="monster" value="#{monster01}"/>
<property name="monsterName" value="#{monster01.name}"/>
<property name="crySound" value="#{spELBean.cry('喵喵的..')}"/>
<property name="bookName" value="#{T(com.llp.spring.bean.SpELBean).read('天龙八部')}"/>
<property name="result" value="#{89*1.2}"/>
</bean>
@Test
public void setBeanBySpel() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans04.xml");
SpELBean spELBean = ioc.getBean("spELBean", SpELBean.class);
System.out.println("spELBean=" + spELBean);
}
测试结果
|