spring源码解析-(1)关于Bean

作者 : admin 本文共7106个字,预计阅读时间需要18分钟 发布时间: 2024-06-9 共2人阅读

什么是Bean?

spring对所有注入到IoC容器中的类的统称。

我们要注册进入spirng的bean千奇百怪,所以spring必须需要使用一个统一的定义来标识bean,就有了接下来的BeandDefinition,通过名称我们就可以知道,他是对bean的定义。

Spring的BeanDefinition详解

效果:将不同来源的bean进行归一化处理

什么是BeandDefinition? 下面是BeanDefinition的源码,BeanDefinition是一个接口,他继承了两个接口,分别是AttributeAccessor和BeanMetadataElement。

简单来说,spring将所有需要装在到容器中的类进行了归一化处理,他们的共同属性都通过BeanDefinition去约束。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
void setScope(@Nullable String scope);
@Nullable
String getScope();
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
void setPrimary(boolean primary);
boolean isPrimary();
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();
void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();
void setRole(int role);
int getRole();
void setDescription(@Nullable String description);
@Nullable
String getDescription();
ResolvableType getResolvableType();
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
@Nullable
String getResourceDescription();
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}

从代码中,我们可以看出,BeanDefinition一共有两种实现类型,一种是AnnotatedBeanDefinition,另一种则是AbstractBeanDefinition。

不难看出,AnnotatedBeanDefinition是对BeanDefinition接口的扩展,而AbstractBeanDefinition是一个抽象方法, 实现了大部分的模板方法,以便子类去使用。

spring源码解析-(1)关于Bean插图

有了存储类的统一元数据结构,那么spring将需要一种特定的数据结构去存储这些内容,spring提供了这么一个接口BeanDefinitionRegistry,能力如下:

public interface BeanDefinitionRegistry extends AliasRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
boolean containsBeanDefinition(String beanName);
String[] getBeanDefinitionNames();
int getBeanDefinitionCount();
boolean isBeanNameInUse(String beanName);
}

通过BeanDefinitionRegistry中提供的方法中我们可以看到他拥有什么能力,首先将名称和对应的beanDefinition进行匹配。

其次,通过getBeanDefinitionNames,不难看出我们可以一个beandefinition可以拥有多个别名。

可以通过BeanDefinitionRegistry的实现类来窥探spring究竟是如何存储的,其实很简单,是通过一个map进行存储的。

具体代码如下:

public class SimpleBeanDefinitionRegistry extends SimpleAliasRegistry implements BeanDefinitionRegistry {
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "'beanName' must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
this.beanDefinitionMap.put(beanName, beanDefinition);
}
@Override
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
if (this.beanDefinitionMap.remove(beanName) == null) {
throw new NoSuchBeanDefinitionException(beanName);
}
}
@Override
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
if (bd == null) {
throw new NoSuchBeanDefinitionException(beanName);
}
return bd;
}
@Override
public boolean containsBeanDefinition(String beanName) {
return this.beanDefinitionMap.containsKey(beanName);
}
@Override
public String[] getBeanDefinitionNames() {
return StringUtils.toStringArray(this.beanDefinitionMap.keySet());
}
@Override
public int getBeanDefinitionCount() {
return this.beanDefinitionMap.size();
}
@Override
public boolean isBeanNameInUse(String beanName) {
return isAlias(beanName) || containsBeanDefinition(beanName);
}
}

通过registerBeanDefinition方法可以看出,将beanName与beanDefinition进行绑定,多个beanName可以绑定同一个beanDefinition。

怎样去使用BeanDefinition的实现类呢?

首先创建一个实体类:

@Component // 后面测试注解的方式用到的
public class Person {
private Integer id;
private String name;
public Person() {
}
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
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;
}
}

1、通过读取xml中的数据

xml代码如下:


<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="person" class="com.test.entity.Person">
<property name="id" value="1"/>
<property name="name" value="不会敲代码的吕小桥"/>
</bean>
</beans>

测试类:

BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
BeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.loadBeanDefinitions("test.xml");
System.out.println(registry.getBeanDefinitionCount());

输出内容:

> Task :spring-test:BeanDefinitionTest.main()
1

2、通过注解的方式读取bean

注意:Person类需要加上Component注解

测试方法

BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);
reader.register(Person.class);
System.out.println(registry.getBeanDefinitionNames());

输出如下:

org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
person
org.springframework.context.event.internalEventListenerFactory
org.springframework.context.annotation.internalAutowiredAnnotationProcessor

3、通过包扫描的方式读取bean

测试方法:

// 扫描指定包下的所有类
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
// 扫描指定包下的所有类
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
scanner.scan("com.test.entity");
for (String beanDefinitionName : registry.getBeanDefinitionNames()) {
System.err.println(beanDefinitionName);
}

输出结果:

org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
person
org.springframework.context.event.internalEventListenerFactory
org.springframework.context.annotation.internalAutowiredAnnotationProcessor

思考总结:

1、在查看源码的过程中,发现源码中有很多地方用到了如下代码:

Assert.hasText(beanName, "'beanName' must not be empty");

以上代码可以有效的避免我们在开发中大量的if判断,同时可以让你的代码可阅读性更高。

hutools和spring依赖中均有该类型的写法,可以参考一下。

2、设计模式&接口&抽象类,帮助更好的处理一系列方法

在面对一系列处理的时候,我们应该抽象出接口,并使用抽象类去约定模板方法,继而使用子类去实现,这种方式会节省我们大量重复的工作,而且所有的方法都有迹可循,在模板方法中定义流程,在子类中实现,能够有效的解耦流程和实现。这样我们就可以只关心子类的具体实现了。

本站无任何商业行为
个人在线分享 » spring源码解析-(1)关于Bean
E-->