BeanDefinition

A BeanDefinition describes a bean instance, which has property values,
Constructor arguments values, and further information supplied by concrete implementations.
This is just a minimal interface: The main intention is to allow a BeanFactoryPostProcessor to introspect and modify property values and other bean metadata.

BeanDefinition 类图

BeanDefinition: 顶级父接口,继承了BeanMetadataElement和AttributeAccessor.

AbstractBeanDefinition:是GenericBeanDefinition、RootBeanDefinition、ChildBeanDefinition 的通用属性的完整实现。
GenericBeanDefinition: 标准的bean定义目的的一站式服务类.
RootBeanDefinition: 根Bean定义,代表合并的BeanDefinition。
ChildBeanDefinition: 有parent的BeanDefinition

BeanDefinition是SpringFramework中定义的配置元信息接口,包含了:

  • Bean 的类名
  • Bean 的行为配置元素,如作用域、自动绑定模式、生命周期回调等
  • 其他Bean引用,(Collaborators、Dependends)
  • 配置设置(Bean的Properties)

BeanDefinition 元信息

属性 说明
Class Bean的全限类名,必须是具体类
Name Bean的名称或者🆔
Scope Bean的作用域,singleton、prototype
Constructor arguments Bean的构造器参数 for DI
Properties Bean的属性设置 for DI
Autowiring Mode Bean的自动绑定模式:ByName 、 byType
Lazy Initialization Mode Bean 延迟初始化模式
initialzation method Bean初始化回调方法名称
destruction method Bean 销毁回调方法名称

BeanDefinition 构建

  • 通过BeanDefinitionBuilder构建Beandefinition
1
2
3
4
5
6
7
        //bean definition builder.
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);

beanDefinitionBuilder.addPropertyValue("id",1L);
beanDefinitionBuilder.addPropertyValue("name","lisi");

BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
  • 通过GenericBeanDefinition 构建
1
2
3
4
5
6
7
8
9
10
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(User.class);

MutablePropertyValues propertyValues = new MutablePropertyValues();
// propertyValues.addPropertyValue("id",2L);
// propertyValues.addPropertyValue("name","zhaowu");

propertyValues.add("id",2L)
.add("name","zhaowu");
genericBeanDefinition.setPropertyValues(propertyValues);

SpringBean 命名

每个Bean拥有一个或者多个标识符,这些标识符在Bean所在的容器必须是唯一的。
通常,一个Bean仅有一个标识符,可以考虑使用别名来扩充。

在基于XML的配置元信息中,可以使用id或者name属性来规定Bean的标识符。通常Bean的标识符由字母组成,允许出现特殊字符。可以在Bean的name属性使用逗号“,”或者“;”或者空格来间隔名称做为别名。

Bean的id或者name属性如果为空,容器会为Bean自动生成一个唯一的名称。

BeanNameGenerator

BeanNameGenerator 类图

DefaultBeanNameGenerator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* Generate a bean name for the given bean definition, unique within the
* given bean factory.
* @param definition the bean definition to generate a bean name for
* @param registry the bean factory that the definition is going to be
* registered with (to check for existing bean names)
* @param isInnerBean whether the given bean definition will be registered
* as inner bean or as top-level bean (allowing for special name generation
* for inner beans versus top-level beans)
* @return the generated bean name
* @throws BeanDefinitionStoreException if no unique name can be generated
* for the given bean definition
*/
public static String generateBeanName(
BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
throws BeanDefinitionStoreException {

String generatedBeanName = definition.getBeanClassName();
if (generatedBeanName == null) {
if (definition.getParentName() != null) {
generatedBeanName = definition.getParentName() + "$child";
}
else if (definition.getFactoryBeanName() != null) {
generatedBeanName = definition.getFactoryBeanName() + "$created";
}
}
if (!StringUtils.hasText(generatedBeanName)) {
throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
}

String id = generatedBeanName;
if (isInnerBean) {
// Inner bean: generate identity hashcode suffix.
id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
}
else {
// Top-level bean: use plain class name with unique suffix if necessary.
return uniqueBeanName(generatedBeanName, registry);
}
return id;
}

由代码可以看出, 首先获取BeanClassName, BeanClassName 为空时,获取ParentName,ParentName为空时获取FactoryBeanName, 当三者都为空的时候名称是无法创建的。 三者不为空时生成的名称前缀为:
BeanClassName
ParentName$child
FactoryBeanName$created

在生成名字时,如果是内部类, 则生成名字为前缀+#+当前beanDefinition的hashCode, 如下:
BeanClassName#hashCode
ParentName$child#hashCode
FactoryBeanName$created#hashCode

如果不是内部类, 则调用uniqueBeanName生成唯一的BeanName,格式为 + “#” + 序号。

BeanClassName#1
ParentName$child#1
FactoryBeanName$created#1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Turn the given bean name into a unique bean name for the given bean factory,
* appending a unique counter as suffix if necessary.
* @param beanName the original bean name
* @param registry the bean factory that the definition is going to be
* registered with (to check for existing bean names)
* @return the unique bean name to use
* @since 5.1
*/
public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) {
String id = beanName;
int counter = -1;

// Increase counter until the id is unique.
while (counter == -1 || registry.containsBeanDefinition(id)) {
counter++;
id = beanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
}
return id;
}

AnnotationBeanNameGeneritor

先判断是否为AnnotatedBeanDefinition, 优先按照AnnotationBeanDefinition配置的Value获取,如果没有配置,则按照缺省的方式来生成beanName(如果是mypackage.MyJdbcDao 则生成 myJdbcDao)。

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
return buildDefaultBeanName(definition, registry);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Derive a default bean name from the given bean definition.
* <p>The default implementation simply builds a decapitalized version
* of the short class name: e.g. "mypackage.MyJdbcDao" -> "myJdbcDao".
* <p>Note that inner classes will thus have names of the form
* "outerClassName.InnerClassName", which because of the period in the
* name may be an issue if you are autowiring by name.
* @param definition the bean definition to build a bean name for
* @return the default bean name (never {@code null})
*/
protected String buildDefaultBeanName(BeanDefinition definition) {
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
String shortClassName = ClassUtils.getShortName(beanClassName);
return Introspector.decapitalize(shortClassName);
}

BeanDefinition 配置

Xml

1
2
3
4
5
6
7
8
9
10
11
12
<bean id="user" class="com.github.springframework.models.User" primary="true">
<property name="id" value="1"/>
<property name="name" value="zhangsan"/>
</bean>

<bean id="superUser" class="com.github.springframework.models.SuperUser" parent="user" >
<property name="addr" value="上海"/>
</bean>

<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>

Java注解 @Bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class AnnotationBeanDefinitionDemo {


public static void main(String[] args) {

//create factory bean
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

//register config class.
applicationContext.register(Config.class);

//refresh
applicationContext.refresh();

//getUser
System.out.println(applicationContext.getBean(User.class));
}



static class Config{
@Bean
public User user(){
User user = new User();
user.setId(1L);
user.setName("Ann: zhangsan");
return user;
}
}
}

Java注解 @Component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class AnnotationBeanDefinitionDemo {
public static void main(String[] args) {
//create factory bean
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

//register config class.
applicationContext.register(Config.class);

//refresh
applicationContext.refresh();

//
System.out.println(applicationContext.getBean(Config.class));
}
@Component
static class Config{
@Bean
public User user(){
User user = new User();
user.setId(1L);
user.setName("Ann: zhangsan");
return user;
}
}
}

BeanDefinition注册到容器

BeanDefinitionRegistry 提供了 BeanDefinition 的注册、删除,获取,判断是否存在等功能。

BeanDefinitionRegistry 类图1

BeanDefinitionRegistry 类图2

1
2
3
4
5
6
7
8
9
10
static void beanDefinitionRegistry(BeanDefinitionRegistry registry, String name) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
beanDefinitionBuilder.addPropertyValue("id", 1L)
.addPropertyValue("name", "Reg: zhangsan");
if (StringUtils.hasText(name)) {
registry.registerBeanDefinition(name, beanDefinitionBuilder.getBeanDefinition());
} else {
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(),registry);
}
}

由于AnnotatinoConfigApplicationContext 是 BeanDefinitionRegistry的间接子类。

1
2
3
4
5
6
7
8
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Config.class);
beanDefinitionRegistry(applicationContext,"REG:ZhangSan:Name");
beanDefinitionRegistry(applicationContext,null);
applicationContext.refresh();
System.out.println(applicationContext.getBeansOfType(Config.class));
System.out.println(applicationContext.getBeansOfType(User.class));
System.out.println(applicationContext.getBeansOfType(AnnotationApplicationContextDemo.class));

Bean 实例化

常规:

  • 通过构造器(配置元信息:XML、Java注解、JavaAPI)

  • 静态工厂方法(配置元信息:XML、JavaAPI)

1
2
3
4
5
6
7
8
9
10
public class User2 {

private Long id;

private String name;

public static User2 getInstance(){
return new User2();
}
}
1
<bean id="user-by-static-method" class="com.github.spring.beans.User2"  factory-method="getInstance"></bean>
1
2
3
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-creation-context.xml");

User2 user = applicationContext.getBean("user-by-static-method", User2.class);
  • Bean工厂方法(配置元信息:XML、JavaAPI)
1
2
3
4
5
6
7
8
public interface UserFactory {
default User2 createuser() {
return new User2();
}
}

public class DefaultUserFactory implements UserFactory {
}
1
2
<bean id="userFactory" class="com.github.spring.factory.DefaultUserFactory"/>
<bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createuser"/>
1
2
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-creation-context.xml");
User2 user3 = applicationContext.getBean("user-by-instance-method", User2.class);
  • FactoryBean(XML、Java注解、JavaAPI)
1
2
3
4
5
6
7
8
9
10
11
12
public class UserFactoryBean implements FactoryBean<User2> {

@Override
public User2 getObject() throws Exception {
return User2.getInstance();
}

@Override
public Class<?> getObjectType() {
return User2.class;
}
}
1
<bean id="user-by-factory-bean" class="com.github.spring.factory.UserFactoryBean"/>
1
2
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-creation-context.xml");
User2 user2 = applicationContext.getBean("user-by-factory-method", User2.class);

特殊方式:

  • ServiceLoaderFactoryBean

Java ServiceLoader: 会在classpath:/META-INF/services下加载接口配置文件:

文件名名称为全限定接口名称,内容为全限定实现类

services 配置文件

1
com.github.spring.factory.DefaultUserFactory
1
2
3
4
5
6
7
8
9
10
11
12
public static void demoServiceLoader() {
ServiceLoader<UserFactory> serviceLoader = ServiceLoader.load(UserFactory.class, Thread.currentThread().getContextClassLoader());
displayServiceLoad(serviceLoader);
}

public static void displayServiceLoad(ServiceLoader<UserFactory> serviceLoader) {
Iterator<UserFactory> iterator = serviceLoader.iterator();
while (iterator.hasNext()) {
UserFactory userFactory = iterator.next();
System.out.println(userFactory.createuser());
}
}

ServiceLoaderFactoryBean的实现

1
2
3
<bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
<property name="serviceType" value="com.github.spring.factory.UserFactory"/>
</bean>
1
2
3
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/sp-bean-creation-context.xml");
ServiceLoader<UserFactory> serviceLoader = applicationContext.getBean("userFactoryServiceLoader", ServiceLoader.class);
displayServiceLoad(serviceLoader);
  • AutowireCapableBeanFactory#createBean(java.lang.Class,int, boolean);
1
2
3
AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
UserFactory userFactory = beanFactory.createBean(DefaultUserFactory.class);
System.out.println(userFactory.createuser());
  • BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition);

Bean的初始化

  • @PostConstructor

  • InitializingBean 的 afterPropertiesSet

  • Bean的initMethod
    @Bean(initMethod=””)

    AbstractBeanDefinition.setInitMethodName("");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class DefaultUserFactory implements UserFactory, InitializingBean {

public DefaultUserFactory() {
System.out.println("DefaultUserFactory Constructor Called.");
}

@PostConstruct
public void init(){
System.out.println("DefaultUserFactory PostConstructor Called.");
}

public void initUserFactory(){
System.out.println("DefaultUserFactory initUserFactory Called.");
}

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("DefaultUserFactory afterPropertiesSet called.");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
public class BeanInitializationDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(BeanInitializationDemo.class);
applicationContext.refresh();
UserFactory userFactory = applicationContext.getBean(UserFactory.class)
System.out.println(userFactory.createuser());
applicationContext.close();
}

@Bean(initMethod = "initUserFactory")
public DefaultUserFactory userFactory(){
return new DefaultUserFactory();
}
}

延迟初始化

  • xml:
  • annotation: @Lazy

对于延迟初始化,是在applicationContext初始化之后进行初始化。
非延迟初始化,是在applicationContext初始化之前进行初始化。

Bean 的销毁

  • @PreDestroy
  • 实现DisposableBean接口的destoy()方法
  • Bean的 destroy方法 @Bean(destroy="") AbstractBeanDefinition.setDestroyMethodName("");

  • 如何注册一个Spring Bean

可以通过BeanDefinition和外部单体对象来注册。

1
2
3
4
5
UserFactory userFactory = new DefaultUserFactory();
ConfiguableListableBeanFactory factory = applicationContext.getBeanFactory();
factory.registerSingleton("userFactory", userFactory);

UserFactory userFactory = applicationContext.getBean("UserFactory",UserFactory.class);
  • Spring BeanDefinition 是什么?

  • Spring 容器是如何注册Bean的?