什么是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);@NullableString getParentName();void setBeanClassName(@Nullable String beanClassName);@NullableString getBeanClassName();void setScope(@Nullable String scope);@NullableString getScope();void setLazyInit(boolean lazyInit);boolean isLazyInit();void setDependsOn(@Nullable String... dependsOn);@NullableString[] getDependsOn();void setAutowireCandidate(boolean autowireCandidate);boolean isAutowireCandidate();void setPrimary(boolean primary);boolean isPrimary();void setFactoryBeanName(@Nullable String factoryBeanName);@NullableString getFactoryBeanName();void setFactoryMethodName(@Nullable String factoryMethodName);@NullableString getFactoryMethodName();ConstructorArgumentValues getConstructorArgumentValues();default boolean hasConstructorArgumentValues() {return !getConstructorArgumentValues().isEmpty();}MutablePropertyValues getPropertyValues();default boolean hasPropertyValues() {return !getPropertyValues().isEmpty();}void setInitMethodName(@Nullable String initMethodName);@NullableString getInitMethodName();void setDestroyMethodName(@Nullable String destroyMethodName);@NullableString getDestroyMethodName();void setRole(int role);int getRole();void setDescription(@Nullable String description);@NullableString getDescription();ResolvableType getResolvableType();boolean isSingleton();boolean isPrototype();boolean isAbstract();@NullableString getResourceDescription();@NullableBeanDefinition getOriginatingBeanDefinition();
}
从代码中,我们可以看出,BeanDefinition一共有两种实现类型,一种是AnnotatedBeanDefinition,另一种则是AbstractBeanDefinition。
不难看出,AnnotatedBeanDefinition是对BeanDefinition接口的扩展,而AbstractBeanDefinition是一个抽象方法, 实现了大部分的模板方法,以便子类去使用。
有了存储类的统一元数据结构,那么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);@Overridepublic 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);}@Overridepublic void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {if (this.beanDefinitionMap.remove(beanName) == null) {throw new NoSuchBeanDefinitionException(beanName);}}@Overridepublic BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {BeanDefinition bd = this.beanDefinitionMap.get(beanName);if (bd == null) {throw new NoSuchBeanDefinitionException(beanName);}return bd;}@Overridepublic boolean containsBeanDefinition(String beanName) {return this.beanDefinitionMap.containsKey(beanName);}@Overridepublic String[] getBeanDefinitionNames() {return StringUtils.toStringArray(this.beanDefinitionMap.keySet());}@Overridepublic int getBeanDefinitionCount() {return this.beanDefinitionMap.size();}@Overridepublic 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;}@Overridepublic 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代码如下:
<?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="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、设计模式&接口&抽象类,帮助更好的处理一系列方法
在面对一系列处理的时候,我们应该抽象出接口,并使用抽象类去约定模板方法,继而使用子类去实现,这种方式会节省我们大量重复的工作,而且所有的方法都有迹可循,在模板方法中定义流程,在子类中实现,能够有效的解耦流程和实现。这样我们就可以只关心子类的具体实现了。