Spring Bean的配置、定义、作用域、生命周期、继承
1、Spring bean的配置形式:
a、基于 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 id="user" class="com.xoyar.spring.bean.User"></bean> </beans>
b、基于注解的配置;
c、基于 Java 的配置。
2、Spring Bean 定义
被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的。bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。
3、Spring Bean 作用域。默认作用域为:singleton。
作用域
描述
singleton
该作用域将 bean 的定义的限制在每一个 Spring IoC 容器中的一个单一实例(默认)。
prototype
该作用域将单一 bean 的定义限制在任意数量的对象实例。
request
该作用域将 bean 的定义限制为 HTTP 请求。只在 web-aware Spring ApplicationContext 的上下文中有效。
session
该作用域将 bean 的定义限制为 HTTP 会话。 只在web-aware Spring ApplicationContext的上下文中有效。
global-session
该作用域将 bean 的定义限制为全局 HTTP 会话。只在 web-aware Spring ApplicationContext 的上下文中有效。
我们来测试一下scope分别为不同值时的效果。常用singleton和prototype,这里只测试这两种情况。
1、首先写一个bean类。
package com.xoyar.spring.bean; public class ScopeBean { /** * 实例化对象时需要调用构造函数,所以我们通过构造函数的调用次数来判断是单例还是多例 */ public ScopeBean(){ System.out.println("。。。实例化ScopeBean。。。"); } }
2、在beans.xml中配置ScopeBean这个类
2.1第一次我们先不配置scope标签,它默认是singleton
<!--如果不指定scope的值,默认是singleton--> <bean id="scope" class="com.xoyar.spring.bean.ScopeBean"></bean>
来看看测试结果
2018-11-10 16:32:12 DEBUG [main] org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:448) - Creating instance of bean 'scope' 。。。实例化ScopeBean。。。 2018-11-10 16:32:12 DEBUG [main] org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537) - Eagerly caching bean 'scope' to allow for resolving potential circular references 2018-11-10 16:32:12 DEBUG [main] org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:484) - Finished creating instance of bean 'scope' 2018-11-10 16:32:12 DEBUG [main] org.springframework.context.support.AbstractApplicationContext.initLifecycleProcessor(AbstractApplicationContext.java:773) - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@4923ab24] 2018-11-10 16:32:12 DEBUG [main] org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:251) - Returning cached instance of singleton bean 'lifecycleProcessor' 2018-11-10 16:32:12 DEBUG [main] org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:81) - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties] 2018-11-10 16:32:12 DEBUG [main] org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:81) - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment] 2018-11-10 16:32:12 DEBUG [main] org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:103) - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null] 2018-11-10 16:32:12 DEBUG [main] org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:251) - Returning cached instance of singleton bean 'scope' 2018-11-10 16:32:12 DEBUG [main] org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:251) - Returning cached instance of singleton bean 'scope' beans.xml里面scope是默认值singleton时 ,scope1 : com.xoyar.spring.bean.ScopeBean@1b26f7b2 beans.xml里面scope是默认值singleton时 ,scope2 : com.xoyar.spring.bean.ScopeBean@1b26f7b2
可以看到只运行了一次构造方法。并且scope1和scope2的hash值相同,说明是同一个对象。
2.2、看第二种情况,当scope配置为prototype时。
<bean id="scope" class="com.xoyar.spring.bean.ScopeBean" scope="prototype"></bean>
测试结果为:
2018-11-10 16:39:15 DEBUG [main] org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:448) - Creating instance of bean 'scope' 。。。实例化ScopeBean。。。 2018-11-10 16:39:15 DEBUG [main] org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:484) - Finished creating instance of bean 'scope' 2018-11-10 16:39:15 DEBUG [main] org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:448) - Creating instance of bean 'scope' 。。。实例化ScopeBean。。。 2018-11-10 16:39:15 DEBUG [main] org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:484) - Finished creating instance of bean 'scope' beans.xml里面scope是prototype时 ,scope1 : com.xoyar.spring.bean.ScopeBean@1b26f7b2 beans.xml里面scope是prototype时 ,scope2 : com.xoyar.spring.bean.ScopeBean@491cc5c9
可以看到,构造方法调用了两次。并且hash值不同,说明实例化出了多个对象。
4、Spring Bean 生命周期
理解 Spring bean 的生命周期很容易。当一个 bean 被实例化时,它可能需要执行一些初始化使它转换成可用状态。同样,当 bean 不再需要,并且从容器中移除时,可能需要做一些清除工作。
为了定义安装和拆卸一个 bean,我们只要声明带有 init-method 和/或 destroy-method 参数的 。init-method 属性指定一个方法,在实例化 bean 时,立即调用该方法。同样,destroy-method 指定一个方法,只有从容器中移除 bean 之后,才能调用该方法。
我们来测试一下它的生命周期:
1、编写InitBean类包含init方法。
package com.xoyar.spring.bean; public class InitBean { public void init(){ System.out.println("。。。。。初始化方法。。。。。"); } public void print(){ System.out.println("....打印方法....."); } }
2、在beans.xml文件中配置InitBean类。
<?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 id="user" class="com.xoyar.spring.bean.User"></bean> <!--init-method="init"用来指定初始化方法--> <bean id="init" class="com.xoyar.spring.bean.InitBean" init-method="init"></bean> </beans>
3、现在来测试一下
@Test public void initTest(){ // 创建IOC容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); //参数为xml文件中的id InitBean init = (InitBean) ctx.getBean("init"); System.out.println(init); }
4、打印结果
2018-11-10 16:40:59 DEBUG [main] org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1685) - Invoking init method 'init' on bean with name 'init' 。。。。。初始化方法。。。。。 2018-11-10 16:40:59 DEBUG [main] org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:484) - Finished creating instance of bean 'init' 2018-11-10 16:40:59 DEBUG [main] org.springframework.context.support.AbstractApplicationContext.initLifecycleProcessor(AbstractApplicationContext.java:773) - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@4923ab24] 2018-11-10 16:40:59 DEBUG [main] org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:251) - Returning cached instance of singleton bean 'lifecycleProcessor' 2018-11-10 16:40:59 DEBUG [main] org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:81) - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties] 2018-11-10 16:40:59 DEBUG [main] org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:81) - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment] 2018-11-10 16:40:59 DEBUG [main] org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:103) - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null] 2018-11-10 16:40:59 DEBUG [main] org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:251) - Returning cached instance of singleton bean 'init' com.xoyar.spring.bean.InitBean@1b26f7b2
我们可以看到,在执行测试方法中的System.out.printIn(init);之前执行了初始化方法。destroy方法同理配置destroy-method属性,读者可以自行测试。
5、Spring Bean 定义继承
Spring Bean 定义的继承与 Java 类的继承无关,但是继承的概念是一样的。
我们来测试一下:
5.1先创建两个具有继承关系的类Animal和Dog,但是这里的java类中不需要使用extends关键字,继承关系我们在beans.xml文件中进行配置。
public class Animal { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
public class Dog{ private String name; private String age; //这里依然写上get、set方法。 }
5.2、在beans.xml中进行配置,设置dog的parent属性为animal。
<bean id="animal" class="com.xoyar.spring.bean.Animal"> <property name="name" value="动物"></property> </bean> <bean id="dog" class="com.xoyar.spring.bean.Dog" parent="animal"> <!--<property name="name" value="狗"></property>--> <property name="age" value="6"></property> </bean>
5.3、我们来测试一下。由于继承关系,在不指定dog的name属性时,会继承父类的name属性值。当然,子类配置了自己的name属性时打印子类的配置的name属性值。
@Test public void parentTest(){ // 创建IOC容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); //参数为xml文件中的id Animal animal = (Animal) ctx.getBean("animal"); System.out.println("animal.getName() : "+animal.getName());//动物 Dog dog = (Dog) ctx.getBean("dog"); System.out.println("dog.getName() : "+dog.getName());//动物 System.out.println("dog.getAge() : "+dog.getAge());//6 }