Spring原始碼分析之BeanDefinition
前言
我們定義的所有Bean,不管是通過XML檔案定義的,或者通過@Component註解定義的,或者通過@Bean註解定義的,
最後都會轉換成一系列的BeanDefinition物件,儲存到BeanDefinitionRegistry(登錄檔)中。
BeanDefinition和Bean例項的關係就類似於Java類和Java物件的關係,Spring通過各種來源如XML或JavaConfig來載入BeanDefinition,
後續通過BeanDefinition來建立Bean例項。BeanDefinition中儲存了Bean的所有資訊,如名稱,所屬Class,是否延遲載入等。
BeanDefinition定義
BeanDefinition介面定義如下
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { //預設只提供singleton(單例)和prototype(原型,每次都會建立物件)兩種,但也可以擴充套件 //如基於web的擴充套件的scope有request, session String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; //使用者定義的Bean一般使用這個 int ROLE_APPLICATION = 0; //暫時不知道哪裡使用 int ROLE_SUPPORT = 1; //Spring內部定義的Bean一般使用這個 int ROLE_INFRASTRUCTURE = 2; //所屬父Bean,可以繼承父Bean的配置資訊 void setParentName(String parentName); String getParentName(); //Bean的類名稱,後續要通過反射來建立Bean例項 void setBeanClassName(String beanClassName); String getBeanClassName(); //Bean的scope,一般我們自己定義的Bean預設就是singleton void setScope(String scope); String getScope(); //設定是否懶載入,預設非懶載入(會在建立ApplicationContext的過程中提前建立Bean,懶載入的話就是在第一次getBean()時建立Bean) void setLazyInit(boolean lazyInit); boolean isLazyInit(); //設定該Bean依賴的所有的Bean(這裡的依賴不是指屬性依賴@Autowire這種),而是約定一種依賴關係,如A依賴B,那麼在建立A前必須先建立B void setDependsOn(String... dependsOn); String[] getDependsOn(); //設定該Bean是否可以注入到其他Bean中,只對根據型別注入有效,如果根據名稱注入,即使這邊設定了false也是可以的,預設為true void setAutowireCandidate(boolean autowireCandidate); boolean isAutowireCandidate(); //是否為主要,同一介面的多個實現,如果沒有指定名字,Spring會優先選擇設定primary為true的Bean void setPrimary(boolean primary); boolean isPrimary(); // 如果該Bean使用工廠方法來建立,需要指定工廠Bean名稱。 void setFactoryBeanName(String factoryBeanName); String getFactoryBeanName(); //指定工廠類中的工廠方法名稱 void setFactoryMethodName(String factoryMethodName); String getFactoryMethodName(); //構造器引數 ConstructorArgumentValues getConstructorArgumentValues(); //Bean中的屬性值 MutablePropertyValues getPropertyValues(); //是否為singleton boolean isSingleton(); //是否為prototype boolean isPrototype(); //如果這個Bean被設定為abstract,那麼不能被例項化, boolean isAbstract(); }
相關類圖如下
Spring提供了不同型別的BeanDefinition實現,
ScannedGenericBeanDefinition: 掃描@Component註解載入的BeanDefinition。
ConfigurationClassBeanDefinition: 掃描@Configuration註解類下包含@Bean註解的方法載入的BeanDefinition。
GenericBeanDefinition: 通用的BeanDefinition實現。
BeanDefinitionRegistry
相關類圖如下
DefaultListableBeanFactory就是IOC容器的最終實現類,既實現了BeanFactory介面,也實現了BeanDefinitionRegistry介面,
所以它不僅是Bean容器,也是BeanDefinition登錄檔,同時管理Bean和BeanDefinition。
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
public class TestBeanDefinition {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition(UserService.class);
definitionBuilder.addPropertyValue("username", "lisi");
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
System.out.println("==========");
beanFactory.registerBeanDefinition("userService", definitionBuilder.getBeanDefinition());
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
UserService userService = (UserService) beanFactory.getBean("userService");
System.out.println(userService.getUsername());//lisi
}
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class UserService {
private String username;
}
}
我們可以自己建立一個BeanDefinition,將它註冊到BeanDefinitionRegistry,後續BeanFactory就根據BeanDefinition來建立Bean例項。
DefaultListableBeanFactory內部是通過一個ConcurrentHashMap來儲存Bean名稱和BeanDefinition的對應關係的。
參考
Spring IOC 容器原始碼分析
RootBeanDefinition與GenericBeanDefinition (轉)