通过静态工厂获取对象
package com.spring.factory; import com.spring.beans.Monster; import java.util.HashMap; import java.util.Map; public class MyStaticFactory { private static Map<String, Monster> monsterMap; static { monsterMap = new HashMap<String, Monster>(); monsterMap.put("monster_01", new Monster(100, "黄袍怪", "一阳指")); monsterMap.put("monster_02", new Monster(200, "九头金雕", "如来神掌")); } public static Monster getMonster(String key) { return monsterMap.get(key); } }
<!-- 通过静态工厂来获取bean 对象--> <bean id="my_monster" class="com.spring.factory.MyStaticFactory" factory-method="getMonster"> <!-- constructor-arg 标签提供key --> <constructor-arg value="monster_01"/> </bean>
通过实例工厂获取对象
package com.spring.factory; import com.spring.beans.Monster; import java.util.HashMap; import java.util.Map; public class MyInstanceFactory { private Map<String, Monster> monster_map; //非静态代码块 { monster_map = new HashMap<String, Monster>(); monster_map.put("monster_01", new Monster(100, "猴子精", "吃桃")); monster_map.put("monster_02", new Monster(200, "佛祖", "如来神掌")); } public Monster getMonster(String key) { return monster_map.get(key); } }
<bean id="myInstanceFactory" class="com.spring.factory.MyInstanceFactory"/> <bean id="my_monster2" factory-bean="myInstanceFactory" factory-method="getMonster"> <constructor-arg value="monster_02"/> </bean>
bean 配置信息重用(继承)
在spring 的ioc 容器, 提供了一种继承的方式来实现bean 配置信息的重用。
<!-- 继承的方式来实现bean 配置信息的重用--> <bean id="monster10" class="com.spring.beans.Monster"> <property name="monsterId" value="10"/> <property name="name" value="蜈蚣精"/> <property name="skill" value="蜇人"/> </bean> <!-- parent="monster10" 就是继承使用了monster10 的配置信息--> <bean id="monster11" class="com.spring.beans.Monster" parent="monster10"/> <!-- 当我们把某个bean设置为abstract="true" 这个bean只能被继承,而不能实例化了--> <bean id="monster12" class="com.spring.beans.Monster" abstract="true"> <property name="monsterId" value="12"/> <property name="name" value="美女蛇"/> <property name="skill" value="诱惑"/> </bean> <!-- parent="monster12" 就是继承使用了monster12 的配置信息--> <bean id="monster13" class="com.spring.beans.Monster" parent="monster12"/>
测试
@Test public void getBeanByExtends() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); Monster monster1 = ioc.getBean("monster11", Monster.class); System.out.println(monster1); Monster monster2 = (Monster) ioc.getBean("monster13", Monster.class); System.out.println(monster2); }
bean 创建顺序
- 在spring 的ioc 容器, 默认是按照配置的顺序创建bean 对象
<bean id="student01" class="com.bean.Student" /> <bean id="department01" class="com.bean.Department" />
会先创建student01 这个bean 对象,然后创建department01 这个bean 对象。
- 如果这样配置
<bean id="student01" class="com.bean.Student" depends-on="department01"/> <bean id="department01" class="com.bean.Department" />
会先创建department01 对象,再创建student01 对象.
bean 对象的单例和多例
在spring 的ioc 容器, 在默认是按照单例创建的,即配置一个bean 对象后,ioc 容器只会创建一个bean 实例。
如果我们希望ioc容器配置某个bean 对象,以多个实例形式创建,则可以通过配置scope=“prototype” 来指定。
//配置beans.xml <bean name="car" scope="prototype" class="com.spring.beans.Car"/>
测试
@Test public void getBeanByPrototype() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); for (int i = 0; i < 3; i++) { Car car = ioc.getBean("car", Car.class); System.out.println(car); } }
注意
1. 默认是单例singleton, 在启动容器时, 默认就会创建, 并放入到singletonObjects 集合。 2. 当<bean scope="prototype" > 设置为多实例机制后, 该bean 是在getBean()时才创建。 3. 如果是单例singleton, 同时希望在getBean 时才创建, 可以指定懒加载 lazy-init="true"。 4. 通常情况下, lazy-init 使用默认值false , 在开发看来用空间换时间是值得的, 除非有特殊的要求。 5. 如果scope="prototype" 多实例机制,lazy-init 属性的值不管是ture, 还是false 都是在getBean 时候创建对象。
bean 的生命周期
bean 对象创建是由JVM 完成的。通过如下步骤可以进行测试
- 1.执行构造器。
- 2.执行set 相关方法。
package com.spring.beans; 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()..."); this.name = name; } public void init() { System.out.println("House init().."); } public void destory() { System.out.println("House destory().."); } }
3.调用bean 的初始化的方法(需要配置)。
<!-- 配置bean 的初始化方法和销毁方法--> <bean id="house" class="com.spring.beans.House" init-method="init" destroy-method="destory"> <property name="name" value="深圳"/> </bean>
- 4.使用bean。
- 5.当容器关闭时候,调用bean 的销毁方法(需要配置)。
测试
@Test public void beanLife() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); House house = ioc.getBean("house", House.class); System.out.println(house); ((ConfigurableApplicationContext) ioc).close(); }
注意
- 1.初始化init 方法和destory 方法, 由程序员设置。
- 2.销毁方法当关闭容器时,才会被调用。
配置bean 的后置处理器
- 在spring 的ioc 容器,可以配置bean 的后置处理器。
- 该处理器/对象会在bean 初始化方法调用前和初始化方法调用后被调用。
- 程序员可以在后置处理器中编写自己的代码。
public class MyBeanPostProcessor implements BeanPostProcessor { /** * 在bean 初始化之前完成某些任务 * @param bean : 就是ioc 容器返回的bean 对象, 如果这里被替换会修改,则返 回的bean 对象也会被修改 * @param beanName: 就是ioc 容器配置的bean 的名称 * @return Object: 就是返回的bean 对象 */ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // TODO Auto-generated method stub System.out.println("postProcessBeforeInitialization 被调用" + beanName + " bean= " + bean.getClass()); return bean; } /** * 在bean 初始化之后完成某些任务 * @param bean : 就是ioc 容器返回的bean 对象, 如果这里被替换会修改,则返 回的bean 对象也会被修改 * @param beanName: 就是ioc 容器配置的bean 的名称 * @return Object: 就是返回的bean 对象 */ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization 被调用" + beanName + " bean= " + bean.getClass()); return bean; } }
配置beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 配置bean 的初始化方法和销毁方法--> <bean id="house" class="com.spring.beans.House" init-method="init" destroy-method="destory"> <property name="name" value="北京豪宅"/> </bean> <!-- bean 后置处理器的配置--> <bean id="myBeanPostProcessor" class="com.spring.beans.MyBeanPostProcessor" /> </beans>
测试
@Test public void testBeanPostProcessor() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans02.xml"); House house = ioc.getBean("house", House.class); System.out.println(house); //关闭容器 ((ConfigurableApplicationContext) ioc).close(); }
使用AOP(反射+动态代理+IO+容器+注解)执行后置处理器,可以对IOC 容器中所有的对象进行统一处理,比如日志处理/权限的校验/安全的验证/事务管理。是切面编程的特点。
通过属性文件给bean 注入值
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1. 通过属性文件给bean 注入值, 2. 需要导入: xmlns:context 名字空间,并指定属性文件路径 --> <context:property-placeholder location="classpath:my.properties"/> <bean id="monster10" class="com.spring.beans.Monster"> <property name="monsterId" value="${id}"/> <property name="name" value="${name}"/> <property name="skill" value="${skill}"/> </bean>