文章目录
XML配置spring容器
2.1 获取bean的方式
2.1.1 获取bean方法
- 通过类获取
bean
- 通过
id
获取bean
,获得Object
对象 - 通过
name
获取bean
,获得Object
对象 - 通过
name
+class
获取bean
2.1.2 示例代码
src\main\resources\spring.xml
<!-- ! 1、如何获取 Bean XML 配置 -->
<bean class="com.ieening.NormalBean" id="testGetBeanNormalBeanId"
name="testGetBeanNormalBeanName" />
<alias name="testGetBeanNormalBeanName" alias="testGetBeanNormalBeanNameAlias" />
测试代码
src\test\java\com\ieening\TestGetBean.java
package com.ieening;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestGetBean {
private ClassPathXmlApplicationContext classPathXmlApplicationContext;
@Before
public void setUp() {
classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"spring.xml");
}
/**
* ! 1、通过类获取 bean,注意需要唯一,否则报错
*/
@Test
public void testGetBeanByClass() {
CustomBean customBean = classPathXmlApplicationContext.getBean(CustomBean.class);
assertTrue(customBean instanceof CustomBean);
}
/**
* ! 2、通过 xml 配置文件中配置的 Id 获取 Bean
*/
@Test
public void testGetBeanById() {
Object normalBean = classPathXmlApplicationContext.getBean("testGetBeanNormalBeanId");
assertTrue(normalBean instanceof NormalBean);
}
/**
* ! 3、通过 xml 配置文件中配置的 name 获取 Bean
*/
@Test
public void testGetBeanByName() {
Object normalBean = classPathXmlApplicationContext.getBean("testGetBeanNormalBeanName");
assertTrue(normalBean instanceof NormalBean);
}
/**
* ! 4、通过 xml 配置文件中配置的 name 和类获取 Bean
*/
@Test
public void testGetBeanByNameAndClass() {
Object normalBean = classPathXmlApplicationContext.getBean("testGetBeanNormalBeanName", NormalBean.class);
assertTrue(normalBean instanceof NormalBean);
}
/**
* ! 5、通过 xml 配置文件中配置的别名获取 Bean
*/
@Test
public void testGetBeanByAlias() {
Object normalBean = classPathXmlApplicationContext.getBean("testGetBeanNormalBeanNameAlias");
assertTrue(normalBean instanceof NormalBean);
}
@After
public void tearDown() {
if (classPathXmlApplicationContext != null) {
classPathXmlApplicationContext.close();
}
}
}
2.2 属性注入
在spring
创建对象时,为其属性赋值。属性依赖注⼊的⽅式有三种: Set
注⼊、构造函数注⼊和⾃动注⼊。
2.2.1 set注入
创建对象时,Spring
⼯⼚会通过Set
⽅法为对象的属性赋值。根据属性类不同,可以分为:基本数据类型、Date、Properties和自定义四种数据讨论如何注入属性。
src\main\resources\spring.xml
<!-- ? 2.1 创建对象时,Spring ⼯⼚会通过 Set ⽅法为对象的属性赋值 -->
<bean class="com.ieening.CustomBean" id="testAttributeInjectCustomBeanId">
<property name="attributeInteger" value="1" />
</bean>
<bean class="com.ieening.NormalBean" id="testAttributeInjectWithSetterNormalBeanId">
<!-- * bean attributes -->
<!-- * 2.1.1 基本数据类型 + 字符串类型 + 时间类型(注意格式) -->
<property name="attributeInteger" value="1" />
<property name="attributeString" value="string attribute" />
<property name="attributeDate" value="2024/01/16 08:25:20" />
<!-- * 2.1.2 容器类型:Array、Set、List、Map -->
<property name="attributeStringArray">
<array>
<value>first</value>
<value>second</value>
<value>third</value>
</array>
</property>
<property name="attributeStringSet">
<set>
<value>first</value>
<value>second</value>
<value>third</value>
</set>
</property>
<property name="attributeStringList">
<list>
<value>first</value>
<value>second</value>
<value>third</value>
</list>
</property>
<property name="attributeMap">
<map>
<entry key="first" value="One" />
<entry key="second" value="Two" />
<entry key="third" value="Three" />
</map>
</property>
<!-- * 2.1.3 Properties 类型 -->
<property name="attributeProperties">
<props>
<prop key="first">One</prop>
<prop key="second">Two</prop>
<prop key="third">three</prop>
</props>
</property>
<!-- * 2.1.4 自定义类型 -->
<property name="customBean" ref="testAttributeInjectCustomBeanId"></property>
</bean>
2.2.2 构造函数注入
创建对象时,Spring
⼯⼚会通过构造⽅法为对象的属性赋值,使用constructor-arg
标签通过构造器传递参数值。
src\main\resources\spring.xml
<!-- ? 2.2 创建对象时,Spring ⼯⼚会通过构造⽅法为对象的属性赋值,可以通过构造方法注入属性值 -->
<bean class="com.ieening.NormalBean" id="testAttributeInjectWithConstructorNormalBeanId">
<!-- * bean attributes -->
<!-- * 2.2.1 基本数据类型 + 字符串类型 + 时间类型(注意格式) -->
<constructor-arg name="attributeInteger" value="1" />
<constructor-arg name="attributeString" value="string attribute" />
<constructor-arg name="attributeDate" value="2024/01/16 08:25:20" />
<!-- * 2.2.2 容器类型:Array、Set、List、Map -->
<constructor-arg name="attributeStringArray">
<array>
<value>first</value>
<value>second</value>
<value>third</value>
</array>
</constructor-arg>
<constructor-arg name="attributeStringSet">
<set>
<value>first</value>
<value>second</value>
<value>third</value>
</set>
</constructor-arg>
<constructor-arg name="attributeStringList">
<list>
<value>first</value>
<value>second</value>
<value>third</value>
</list>
</constructor-arg>
<constructor-arg name="attributeMap">
<map>
<entry key="first" value="One" />
<entry key="second" value="Two" />
<entry key="third" value="Three" />
</map>
</constructor-arg>
<!-- * 2.2.3 Properties 类型 -->
<constructor-arg name="attributeProperties">
<props>
<prop key="first">One</prop>
<prop key="second">Two</prop>
<prop key="third">three</prop>
</props>
</constructor-arg>
<!-- * 2.2.4 自定义类型 -->
<constructor-arg name="customBean" ref="testAttributeInjectCustomBeanId" />
</bean>
2.2.3 自动注入
不⽤在配置中指定为哪个属性赋值及赋什么值,由spring
⾃动根据某个“原则(byTape or byName
)”,在⼯⼚中查找⼀个bean
,为属性注⼊属性值。
<!-- ? 2.3 不⽤在配置中指定为哪个属性赋值,及赋什么值,由 spring ⾃动根据某个“原则”,在⼯⼚中查找⼀个 bean,为属性注⼊属性值 -->
<bean class="com.ieening.NormalBean" id="testAttributeInjectWithAutoWireNormalBeanId"
autowire="byType">
<!-- * 2.3.1 根据类型自动注入 CustomBean -->
<property name="attributeProperties">
<props>
<prop key="first">One</prop>
<prop key="second">Two</prop>
<prop key="third">three</prop>
</props>
</property>
</bean>
2.2.4 测试代码
CustomBean
类
package com.ieening;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class CustomBean {
private Integer attributeInteger;
public CustomBean() {
}
}
NormalBean
类
package com.ieening;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
public class NormalBean {
private Integer attributeInteger;
private String attributeString;
private Date attributeDate;
private String[] attributeStringArray;
private Set<String> attributeStringSet;
private List<String> attributeStringList;
private Map<String, String> attributeMap;
private Properties attributeProperties;
private CustomBean customBean;
public NormalBean(CustomBean customBean) {
this.customBean = customBean;
}
public static NormalBean createInstance(CustomBean customBean) {
return new NormalBean(customBean);
}
}
测试函数
src\test\java\com\ieening\TestAttributeInjectBean.java
package com.ieening;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAttributeInjectBean {
private ClassPathXmlApplicationContext classPathXmlApplicationContext;
@Before
public void setUp() {
classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"spring.xml");
}
@Test
public void testAttributeInjectWithSetter() {
NormalBean normalBean = classPathXmlApplicationContext.getBean("testAttributeInjectWithSetterNormalBeanId",
NormalBean.class);
String expectedString = "NormalBean(attributeInteger=1, attributeString=string attribute, attributeDate=Tue Jan 16 08:25:20 CST 2024, attributeStringArray=[first, second, third], attributeStringSet=[first, second, third], attributeStringList=[first, second, third], attributeMap={first=One, second=Two, third=Three}, attributeProperties={third=three, first=One, second=Two}, customBean=CustomBean(attributeInteger=1))";
assertEquals(expectedString, normalBean.toString());
}
@Test
public void testAttributeInjectWithConstructor() {
NormalBean normalBean = classPathXmlApplicationContext.getBean("testAttributeInjectWithConstructorNormalBeanId",
NormalBean.class);
String expectedString = "NormalBean(attributeInteger=1, attributeString=string attribute, attributeDate=Tue Jan 16 08:25:20 CST 2024, attributeStringArray=[first, second, third], attributeStringSet=[first, second, third], attributeStringList=[first, second, third], attributeMap={first=One, second=Two, third=Three}, attributeProperties={third=three, first=One, second=Two}, customBean=CustomBean(attributeInteger=1))";
assertEquals(expectedString, normalBean.toString());
}
@Test
public void testAttributeInjectWithAutoWire() {
NormalBean normalBean = classPathXmlApplicationContext.getBean("testAttributeInjectWithAutoWireNormalBeanId",
NormalBean.class);
String expectedString = "NormalBean(attributeInteger=null, attributeString=null, attributeDate=null, attributeStringArray=null, attributeStringSet=null, attributeStringList=null, attributeMap=null, attributeProperties={third=three, first=One, second=Two}, customBean=CustomBean(attributeInteger=1))";
assertEquals(expectedString, normalBean.toString());
}
@After
public void tearDown() {
if (classPathXmlApplicationContext != null) {
classPathXmlApplicationContext.close();
}
}
}
2.3 实例化Bean
bean
基本上就是⽤来创建⼀个或多个对象的配置,当需要bean
的时候,容器会查找配置并且根据bean
定义封装的元数据来创建(或获取)实际对象。如果你使⽤基于 XML
的配置,那么可以在 元素中通过class
属性来指定对象类型。class
属性实际上就是 BeanDefinition
实例中的class
属性。实例化bean
一般有三种方式,通过构造器实例化、通过静态⼯⼚⽅法实例化、通过实例⼯⼚⽅法实例化。
2.3.1 通过构造器实例化
当通过构造器创建 Bean
时,Spring
兼容所有可以使⽤的普通类,也就是说,正在开发的类不需要实现任何特定接⼝或以特定⽅式编码。只要指定 bean
类就⾜够了。 但是,根据您为该特定 bean
使⽤的 IoC
类型,您可能需要⼀个默认(空)构造函数。
src\main\resources\spring_high_order.xml
<!-- ? 1.1 通过构造器实例化 bean -->
<bean class="com.ieening.NormalBean" id="testInstanceBeanWithConstructorId"
name="testInstanceBeanWithConstructorName" />
2.3.2 通过静态⼯⼚⽅法实例化
当采⽤静态⼯⼚⽅法创建 bean
时,除了需要指定 class
属性外,还需要通过 factory-method
属性来指定创建 bean
实例的⼯⼚⽅法。Spring
将会调⽤此⽅法(可以使用constructor-arg
标签传递值)返回实例对象。从这样看来,它与通过普通构造器创建类实例没什么两样。
src\main\resources\spring_high_order.xml
<!-- ? 1.2 通过静态⼯⼚⽅法实例化 bean -->
<import resource="spring.xml" />
<bean class="com.ieening.NormalBean" id="testInstanceBeanWithStaticFactoryMethodId"
factory-method="createInstance" depends-on="testAttributeInjectCustomBeanId">
<constructor-arg name="customBean" ref="testAttributeInjectCustomBeanId" />
</bean>
2.3.3 通过实例⼯⼚⽅法实例化
通过调⽤⼯⼚实例的⾮静态⽅法进⾏实例化与通过静态⼯⼚⽅法实例化类似,请将 class
属性保留为空,并在 factory-bean
,属性中指定当前(或⽗级或祖先) 容器中 bean
的名称,该容器包含要调⽤以创建对象的实例⽅法。使⽤ factory-method
属性设置⼯⼚⽅法本身的名称。
src\main\resources\spring_high_order.xml
<!-- ? 1.3 通过实例⼯⼚⽅法实例化 bean -->
<bean class="com.ieening.BeanFactory" id="beanFactoryId" />
<bean factory-bean="beanFactoryId" factory-method="createNormalBean"
id="testNormalBeanWithInstanceFactoryMethod">
</bean>
src\main\java\com\ieening\BeanFactory.java
package com.ieening;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class BeanFactory {
public NormalBean createNormalBean() {
return new NormalBean();
}
}
2.3.4 测试代码
src\test\java\com\ieening\TestInstanceBean.java
package com.ieening;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestInstanceBean {
private ClassPathXmlApplicationContext classPathXmlApplicationContext;
@Before
public void setUp() {
classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"spring_high_order.xml");
}
/**
* ! 1、使用构造器实例化 bean
*/
@Test
public void testInstanceBeanWithConstructor() {
Object normalBean = classPathXmlApplicationContext.getBean("testInstanceBeanWithConstructorId");
assertTrue(normalBean instanceof NormalBean);
}
/**
* ! 2、使用静态构造方法实例化 bean
*/
@Test
public void testInstanceBeanWithStaticFactoryMethod() {
Object normalBean = classPathXmlApplicationContext.getBean("testInstanceBeanWithStaticFactoryMethodId");
assertTrue(normalBean instanceof NormalBean);
int attributeInteger = ((NormalBean) normalBean).getCustomBean().getAttributeInteger();
assertEquals(1, attributeInteger);
}
/**
* ! 3、使用实例⼯⼚⽅法实例化 bean
*/
@Test
public void testInstanceBeanWithInstanceFactoryMethod() {
Object normalBean = classPathXmlApplicationContext.getBean("testNormalBeanWithInstanceFactoryMethod");
assertTrue(normalBean instanceof NormalBean);
}
@After
public void tearDown() {
if (classPathXmlApplicationContext != null) {
classPathXmlApplicationContext.close();
}
}
}
2.4 bean作用域
2.4.1 bean 作用域介绍
创建bean
定义时,同时也会定义该如何创建Bean
实例。这些具体创建的过程是很重要的,因为它意味着像创建类⼀样,您可以通过简单的定义来创建许多bean
的实例。您不仅可以将不同的依赖注⼊到bean
中,还可以配置bean
的作⽤域。这种⽅法是⾮常强⼤⽽且也⾮常灵活,开发者可以通过配置来指定对象的作⽤域,⽆需在Java
类的层次上配置。bean
可以配置多种作⽤域,Spring
框架⽀持六种作⽤域,有四种作⽤域是当开发者使⽤基于Web
的ApplicationContext
的时候才有效的。
下表描述了⽀持的作⽤域:
Scope | Description |
---|---|
singleton | (默认)每⼀Spring IOC 容器都拥有唯⼀的实例对象 |
prototype | ⼀个Bean 定义可以创建任意多个实例对象,每次使⽤时都会创建⼀个新的bean |
request | 将单个bean 作⽤域限定为单个HTTP 请求的⽣命周期。也就是说,每个HTTP 请求都有⾃⼰的bean 实例。它是在单个bean 定义的后⾯创建的。只有基于Web ]的Spring ApplicationContext 的才可⽤ |
session | 将单个bean 作⽤域限定为HTTP Session 的⽣命周期。只有基于Web 的Spring ApplicationContext 的才可⽤ |
application | 将单个bean 作⽤域限定为ServletContext 的⽣命周期. 只有基于Web 的Spring ApplicationContext 的才可⽤ |
websocket | 将单个bean 作⽤域限定为WebSocket 的⽣命周期。只有基于Web 的Spring ApplicationContext 的才可⽤ |
2.4.2 测试代码
<!-- ! 3、bean 作用域 -->
<bean class="com.ieening.SingletonScopeBean" id="testSingletonScopeBeanId" scope="singleton"></bean>
<bean class="com.ieening.PrototypeScopeBean" id="testPrototypeScopeBeanId" scope="prototype"></bean>
src\test\java\com\ieening\TestBeanScope.java
package com.ieening;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestBeanScope {
private ClassPathXmlApplicationContext classPathXmlApplicationContext;
@Before
public void setUp() {
classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"spring_high_order.xml");
}
/**
* ! 1、测试 Singleton 作用域
*/
@Test
public void testSingleton() {
Object firstBean = classPathXmlApplicationContext.getBean("testSingletonScopeBeanId");
Object secondBean = classPathXmlApplicationContext.getBean("testSingletonScopeBeanId");
assertEquals(firstBean, secondBean);
}
/**
* ! 2、测试 Prototype 作用域
*/
@Test
public void testPrototype() {
Object firstBean = classPathXmlApplicationContext.getBean("testPrototypeScopeBeanId");
Object secondBean = classPathXmlApplicationContext.getBean("testPrototypeScopeBeanId");
assertTrue(firstBean != secondBean);
}
@After
public void tearDown() {
if (classPathXmlApplicationContext != null) {
classPathXmlApplicationContext.close();
}
}
}
2.5 生命周期回调
2.5.1 生命周期回调介绍
Spring
在创建和销毁bean
时,提供了回调函数,分别在调⽤afterPropertiesSet()
之后和destroy()
之前会允许bean
在初始化和销毁bean
时执⾏回调操作。
实现回调有三种方式:
- 第一种:实现
InitializingBean
和DisposableBean
接⼝; - 第二种:在基于
XML
的元数据配置上,开发者可以使⽤init-method
和destroy-method
属性来指定回调方法; - 第三种:使用
@PostConstruct
和@PreDestroy
注解;
因为有三种方法提供回调函数,当出现了多个生命周期机制时,⽽且每个机制都配置了不同的⽅法名字时,每个配置的⽅法会按照以下描述的顺序来执⾏:
- 包含
@PostConstruct
注解的⽅法; - 在
InitializingBean
接⼝中的afterPropertiesSet()
; - ⾃定义的
init()
⽅法;
Destroy
⽅法以相同的顺序调⽤:
- 包含
@PreDestroy
注解的⽅法; - 在
DisposableBean
接⼝中的; - 自定义
destroy()
⽅法;
可以在Beans
元素属性上设定default-init-method
和default-destroy-method
上设定默认的init
和destroy
方法。
2.5.2 测试代码
src\main\resources\spring_high_order.xml
<!-- ! 2、生命周期回调 -->
<!-- ? 2.1 实现接口 -->
<bean class="com.ieening.LifecycleBeanWithInterface" id="testLifecycleBeanWithInterfaceId"
lazy-init="true"></bean>
<!-- ? 2.2 init-method 和 destroy-method -->
<bean class="com.ieening.LifecycleBeanWithInitDestroyMethod"
id="testLifecycleBeanWithInitDestroyMethodId" init-method="init" destroy-method="destroy"
lazy-init="true" />
src\test\java\com\ieening\TestLifecycleBean.java
package com.ieening;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestLifecycleBean {
@Test
public void testLazyInit() {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"spring_high_order.xml");
assertEquals(0, LifecycleBeanWithInterface.getCount());
classPathXmlApplicationContext.getBean("testLifecycleBeanWithInterfaceId");
assertEquals(1, LifecycleBeanWithInterface.getCount());
classPathXmlApplicationContext.close();
}
/**
* ! 1、测试接口生命周期回调函数
*/
@Test
public void testLifecycleBeanWithInterface() {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"spring_high_order.xml");
LifecycleBeanWithInterface.setAfterPropertiesSet(false);
;
LifecycleBeanWithInterface.setDestroy(false);
classPathXmlApplicationContext.getBean("testLifecycleBeanWithInterfaceId");
assertTrue(LifecycleBeanWithInterface.isAfterPropertiesSet());
classPathXmlApplicationContext.close();
assertTrue(LifecycleBeanWithInterface.isDestroy());
}
/**
* ! 2、测试 XML配置生命周期回调函数
*/
@Test
public void testLifecycleBeanWithInitDestroyMethod() {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"spring_high_order.xml");
LifecycleBeanWithInitDestroyMethod.setAfterPropertiesSet(false);
LifecycleBeanWithInitDestroyMethod.setDestroy(false);
classPathXmlApplicationContext.getBean("testLifecycleBeanWithInitDestroyMethodId");
assertTrue(LifecycleBeanWithInitDestroyMethod.isAfterPropertiesSet());
classPathXmlApplicationContext.close();
assertTrue(LifecycleBeanWithInitDestroyMethod.isDestroy());
}
}
src\main\java\com\ieening\LifecycleBeanWithInterface.java
package com.ieening;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class LifecycleBeanWithInterface implements InitializingBean, DisposableBean {
private static int count = 0;
public static int getCount() {
return count;
}
private static boolean afterPropertiesSet = false;
public static void setAfterPropertiesSet(boolean afterPropertiesSet) {
LifecycleBeanWithInterface.afterPropertiesSet = afterPropertiesSet;
}
public static boolean isAfterPropertiesSet() {
return afterPropertiesSet;
}
private static boolean destroy = false;
public static void setDestroy(boolean destroy) {
LifecycleBeanWithInterface.destroy = destroy;
}
public static boolean isDestroy() {
return destroy;
}
@Override
public void destroy() throws Exception {
destroy = true;
}
@Override
public void afterPropertiesSet() throws Exception {
afterPropertiesSet = true;
}
public LifecycleBeanWithInterface() {
count += 1;
}
}
src\main\java\com\ieening\LifecycleBeanWithInitDestroyMethod.java
package com.ieening;
public class LifecycleBeanWithInitDestroyMethod {
private static boolean afterPropertiesSet = false;
public static void setAfterPropertiesSet(boolean afterPropertiesSet) {
LifecycleBeanWithInitDestroyMethod.afterPropertiesSet = afterPropertiesSet;
}
public static boolean isAfterPropertiesSet() {
return afterPropertiesSet;
}
private static boolean destroy = false;
public static void setDestroy(boolean destroy) {
LifecycleBeanWithInitDestroyMethod.destroy = destroy;
}
public static boolean isDestroy() {
return destroy;
}
public void init() {
afterPropertiesSet = true;
}
public void destroy() {
destroy = true;
}
}