用过spring的人都知道,我们将对象注入到spring容器中,交给spring来帮我们管理。这种对象我们称之为bean对象。但是这些bean对象在spring容器中,到底是以什么形式存在,具有哪些属性、行为呢?今天我们进入到spring源码来一探究竟
1 简述 bean的创建工厂BeanFactory有个默认实现类DefaultListableBeanFactory,内部有个存放所有注入bean对象信息的Map
1 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256 );
BeanDefinition基本信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public interface BeanDefinition extends AttributeAccessor , BeanMetadataElement { ...... void setParentName (String parentName) ; String getParentName () ; void setBeanClassName (String beanClassName) ; String getBeanClassName () ; void setScope (String scope) ; ...... }
【AttributeAccessor接口】
类似于map,具有保存和访问name/value属性的能力。
1 2 3 4 5 6 7 8 9 10 11 12 public interface AttributeAccessor { void setAttribute (String var1, @Nullable Object var2) ; @Nullable Object getAttribute (String var1) ; @Nullable Object removeAttribute (String var1) ; boolean hasAttribute (String var1) ; String[] attributeNames(); }
【BeanMetadataElement接口】
具有访问source(配置源)的能力。
1 2 3 4 5 6 public class BeanDefinitionHolder implements BeanMetadataElement { private final BeanDefinition beanDefinition; private final String beanName; @Nullable private final String[] aliases; }
测试示例
假设有以下两个bean,Java代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Description;public class MyTestBean { @Autowired private AutowireCandidateBean autowireCandidateBean; public void init () { System.out.println("inti MyTestBean" ); } public AutowireCandidateBean getAutowireCandidateBean () { return autowireCandidateBean; } public void setAutowireCandidateBean (AutowireCandidateBean bean) { this .autowireCandidateBean = bean; } }
1 2 3 4 5 6 7 8 9 public class AutowireCandidateBean { public void initBean () { System.out.println("init AutowireCandidateBean" ); } public void destroyBean () { System.out.println("destroy AutowireCandidateBean" ); } }
在配置文件applicationContext.xml来进行配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <bean id="myTestBean" class ="com.yuanweiquan.learn.bean.MyTestBean" depends-on="autowireCandidateBean" init-method="init" /> <bean id="autowireCandidateBean" class ="com.yuanweiquan.learn.bean.AutowireCandidateBean" init-method="initBean" autowire-candidate="true" destroy-method="destroyBean" scope="singleton" parent="myTestBean" lazy-init="default" primary="true" > <description>autowireCandidateBean description</description> </bean>
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 FileSystemXmlApplicationContext factory = new FileSystemXmlApplicationContext("classpath:applicationContext.xml" ); BeanDefinition myTestBeanDefinition = factory.getBeanFactory().getBeanDefinition("autowireCandidateBean" ); System.out.println("bean description:" + myTestBeanDefinition.getDescription()); System.out.println("bean class name:" + myTestBeanDefinition.getBeanClassName()); System.out.println("parent name:" + myTestBeanDefinition.getParentName()); System.out.println("scope:" + myTestBeanDefinition.getScope()); System.out.println("is lazyinit:" + myTestBeanDefinition.isLazyInit()); System.out.println("depends On:" + myTestBeanDefinition.getDependsOn()); System.out.println("is autowireCandidate:" + myTestBeanDefinition.isAutowireCandidate()); System.out.println("is primary:" + myTestBeanDefinition.isPrimary()); System.out.println("factory bean name:" +myTestBeanDefinition.getFactoryBeanName()); System.out.println("factory bean method name:" + myTestBeanDefinition.getFactoryMethodName()); System.out.println("init method name:" + myTestBeanDefinition.getInitMethodName()); System.out.println("destory method name:" + myTestBeanDefinition.getDestroyMethodName()); System.out.println("role:" + myTestBeanDefinition.getRole()); factory.close();
控制台输出如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 init AutowireCandidateBean inti MyTestBean bean description:autowireCandidateBean description bean class name:com.yuanweiquan.learn.bean.AutowireCandidateBean parent name:myTestBean scope:singleton is lazyinit:false depends On:null is autowireCandidate:true is primary:true factory bean name:null factory bean method name:null init method name:initBean destory method name:destroyBean role:0 destroy AutowireCandidateBean
通过上面的信息,我们能清晰的看到各属性对应的值。上述测试代码的目的是让我们大家能看到bean在spring容器中,以什么样子的形式存在,具体有哪些属性,属性的值以及默认值是多少
2 BeanDefinition相关类 BeanDefinition子接口和实现类
AnnotatedBeanDefinition 这个接口可以获取BeanDefinition注解相关数据
1 2 3 4 public interface AnnotatedBeanDefinition extends BeanDefinition { AnnotationMetadata getMetadata () ; MethodMetadata getFactoryMethodMetadata () ; }
AbstractBeanDefinition 这个抽象类的构造方法设置了BeanDefinition的默认属性,重写了equals,hashCode,toString方法。
ChildBeanDefinition 可以从父BeanDefinition中集成构造方法,属性等
RootBeanDefinition 代表一个从配置源(XML,Java Config等)中生成的BeanDefinition
GenericBeanDefinition GenericBeanDefinition是自2.5以后新加入的bean文件配置属性定义类,是ChildBeanDefinition和RootBeanDefinition更好的替代者
AnnotatedGenericBeanDefinition 对应注解@Bean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Component("t") public class Tester { public static void main (String[] args) throws Exception { AnnotatedGenericBeanDefinition beanDefinition=new AnnotatedGenericBeanDefinition(Tester.class); System.out.println(beanDefinition.getMetadata().getAnnotationTypes()); System.out.println(beanDefinition.isSingleton()); System.out.println(beanDefinition.getBeanClassName()); } } ==========输出============== [org.springframework.stereotype.Component] true Tester
BeanDefinitionRegistry 这个接口定义了‘注册/获取BeanDefinition ’的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 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) ; }
实现类一般使用Map保存多个BeanDefinition,如下:
1 Map<String, BeanDefinition> beanDefinitionMap = new HashMap<String, BeanDefinition>();
实现类有SimpleBeanDefinitionRegistry,DefaultListableBeanFactory ,GenericApplicationContext 等。
SimpleBeanDefinitionRegistry SimpleBeanDefinitionRegistry是最基本的实现类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public static void main (String[] args) throws Exception { SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry(); BeanDefinition definition_1 = new GenericBeanDefinition(); registry.registerBeanDefinition("d1" , definition_1); BeanDefinition definition_2 = new RootBeanDefinition(); registry.registerBeanDefinition("d2" , definition_2); System.out.println(registry.containsBeanDefinition("d1" )); System.out.println(registry.getBeanDefinitionCount()); System.out.println(Arrays.toString(registry.getBeanDefinitionNames())); } ================结果================== true 2 [d1, d2]
AnnotationConfigApplicationContext 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public AnnotationConfigApplicationContext () { this .reader = new AnnotatedBeanDefinitionReader(this ); this .scanner = new ClassPathBeanDefinitionScanner(this ); } public AnnotationConfigApplicationContext (DefaultListableBeanFactory beanFactory) { super (beanFactory); this .reader = new AnnotatedBeanDefinitionReader(this ); this .scanner = new ClassPathBeanDefinitionScanner(this ); } public AnnotationConfigApplicationContext (Class<?>... annotatedClasses) { this (); register(annotatedClasses); refresh(); }
从源码中可以看出,空参的构造方法会先初始化sacner和reader,为进行bean的解析注册做准备,而容器里不包含任何Bean信息,从注释可以看出,如果调用空参构造,需要手动调用其register()方法注册配置类,并调用refresh()方法刷新容器,触发容器对注解Bean的载入、解析和注册过程。
BeanFactory初始化入口 从AnnotationConfigApplicationContext父类中,可以找到beanFactory的初始化。GenericApplicationContext#new
1 2 3 public GenericApplicationContext () { this .beanFactory = new DefaultListableBeanFactory(); }
3 解析注册BeanDefinition registerBean Spring 提供两种bean的注册方式,一种时通过扫描路径来加载,另一种则是通过class文件来注册。先来看下class文件注册。
1 2 3 4 5 6 7 8 9 10 11 @Test public void registerAndRefresh () { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(AutowiredConfig.class); context.refresh(); context.getBean("testBean" ); context.getBean("name" ); Map<String, Object> beans = context.getBeansWithAnnotation(Configuration.class); assertEquals(2 , beans.size()); }
AnnotationBeanDefinitionReader#doRegisterBean
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 43 44 45 46 47 48 49 50 51 <T> void doRegisterBean (Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); if (this .conditionEvaluator.shouldSkip(abd.getMetadata())) { return ; } abd.setInstanceSupplier(instanceSupplier); ScopeMetadata scopeMetadata = this .scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = (name != null ? name : this .beanNameGenerator.generateBeanName(abd, this .registry)); AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null ) { for (Class<? extends Annotation> qualifier : qualifiers) { if (Primary.class == qualifier) { abd.setPrimary(true ); } else if (Lazy.class == qualifier) { abd.setLazyInit(true ); } else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } for (BeanDefinitionCustomizer customizer : definitionCustomizers) { customizer.customize(abd); } BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this .registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this .registry); }
可以看出,就是将annotatedClass解析成BeanDefinition,并将bean的属性例如@Lazy等封装进去,接着调用beanFactory的注册:
DefaultListableBeanFactory#registerBeanDefinition
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 public void registerBeanDefinition (String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { BeanDefinition existingDefinition = this .beanDefinitionMap.get(beanName); if (existingDefinition != null ) { this .beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { synchronized (this .beanDefinitionMap) { this .beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<>(this .beanDefinitionNames.size() + 1 ); updatedDefinitions.addAll(this .beanDefinitionNames); updatedDefinitions.add(beanName); this .beanDefinitionNames = updatedDefinitions; if (this .manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<>(this .manualSingletonNames); updatedSingletons.remove(beanName); this .manualSingletonNames = updatedSingletons; } } } else { this .beanDefinitionMap.put(beanName, beanDefinition); this .beanDefinitionNames.add(beanName); this .manualSingletonNames.remove(beanName); } this .frozenBeanDefinitionNames = null ; } }
BeanDefinition的注册分为步:
(1) 从缓存中取出当前bean的BeanDefinition (2) 如果存在,则用当前BeanDefinition覆盖原有的 (3) 如果不存在,判断当前bean是否以及开始创建 (4) 如果没有开始创建,则将当前BeanDefinition,以及beanName放入缓存 (5) 如果已经开始创建,将当前BeanDefinition和beanName放入缓存后,如果当前bean是manual singleton bean,则将当前beanName从manual singleton Bean Name中移出,也就是变成了普通的bean,这里的manual singleton Bean指的是以下几种bean:
scanBean 1 2 3 4 5 6 7 8 9 10 11 12 13 @Test public void scanAndRefresh () { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.scan("org.springframework.context.annotation6" ); context.refresh(); context.getBean(uncapitalize(ConfigForScanning.class.getSimpleName())); context.getBean("testBean" ); context.getBean(uncapitalize(ComponentForScanning.class.getSimpleName())); context.getBean(uncapitalize(Jsr330NamedForScanning.class.getSimpleName())); Map<String, Object> beans = context.getBeansWithAnnotation(Configuration.class); assertEquals(1 , beans.size()); }
还是先看context.scan()方法。主要流程如下:
ClassPathBeanDefinitionScanner#doScan
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 protected Set<BeanDefinitionHolder> doScan (String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified" ); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); for (String basePackage : basePackages) { Set<BeanDefinition> candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { ScopeMetadata scopeMetadata = this .scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); String beanName = this .beanNameGenerator.generateBeanName(candidate, this .registry); if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this .registry); beanDefinitions.add(definitionHolder); registerBeanDefinition(definitionHolder, this .registry); } } } return beanDefinitions; }
这个其实和registerBean差不多,只是多了一步从扫描路径里获取符合的bean并封装到beanDefinition中,然后就是registerBean的流程
ClassPathScanningCandidateComponentProvider#scanCandidateComponents
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 private Set<BeanDefinition> scanCandidateComponents (String basePackage) { Set<BeanDefinition> candidates = new LinkedHashSet<>(); String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this .resourcePattern; Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); for (Resource resource : resources) { if (resource.isReadable()) { MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); if (isCandidateComponent(metadataReader)) { ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setResource(resource); sbd.setSource(resource); if (isCandidateComponent(sbd)) { candidates.add(sbd); } } } return candidates; }
4 手动注册beanDefinition 手动注册bean的两种方式:
实现ImportBeanDefinitionRegistrar
实现BeanDefinitionRegistryPostProcessor
ImportBeanDefinitionRegistrar 手动创建BeanDefinition 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 public class Foo { public void foo () { System.out.println("Foo.foo() invoked!" ); } } public class FooImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions (AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(Foo.class); BeanDefinition beanDefinition = builder.getBeanDefinition(); registry.registerBeanDefinition("foo" ,beanDefinition); } } @SpringBootApplication @Import({FooImportBeanDefinitionRegistrar.class}) public class Demo implements CommandLineRunner { @Autowired private Foo foo; public static void main (String[] args) throws Exception { SpringApplication.run(Demo.class, args); } @Override public void run (String... args) throws Exception { foo.foo(); } }
ClassPathBeanDefinitionScanner 借助spring类ClassPathBeanDefinitionScanner来扫描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 31 32 33 34 public class Foo { public void foo () { System.out.println("Foo.foo() invoked!" ); } } public class FooImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions (AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry); scanner.addIncludeFilter(new AssignableTypeFilter(Foo.class)); scanner.scan("com.study.demo.domain" ); } } @SpringBootApplication @Import({FooImportBeanDefinitionRegistrar.class}) public class Demo implements CommandLineRunner { @Autowired private Foo foo; public static void main (String[] args) throws Exception { SpringApplication.run(Demo.class, args); } @Override public void run (String... args) throws Exception { foo.foo(); } }
BeanDefinitionRegistryPostProcessor 实现BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法。在spring源码中@Configuration @Import等配置类的注解就是通过这种方式实现的,具体实现方式可以参考spring源码
org.springframework.context.annotation.ConfigurationClassPostProcessor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Override public void postProcessBeanDefinitionRegistry (BeanDefinitionRegistry registry) { int registryId = System.identityHashCode(registry); if (this .registriesPostProcessed.contains(registryId)) { throw new IllegalStateException( "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry); } if (this .factoriesPostProcessed.contains(registryId)) { throw new IllegalStateException( "postProcessBeanFactory already called on this post-processor against " + registry); } this .registriesPostProcessed.add(registryId); processConfigBeanDefinitions(registry); }
另外一个可参考的样例是Mybatis,在Mybatis中MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,在这个方法中注册bean的方式同1.3
org.mybatis.spring.mapper.MapperScannerConfigurer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Override public void postProcessBeanDefinitionRegistry (BeanDefinitionRegistry registry) { if (this .processPropertyPlaceHolders) { processPropertyPlaceHolders(); } ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); scanner.setAddToConfig(this .addToConfig); scanner.setAnnotationClass(this .annotationClass); scanner.setMarkerInterface(this .markerInterface); scanner.setSqlSessionFactory(this .sqlSessionFactory); scanner.setSqlSessionTemplate(this .sqlSessionTemplate); scanner.setSqlSessionFactoryBeanName(this .sqlSessionFactoryBeanName); scanner.setSqlSessionTemplateBeanName(this .sqlSessionTemplateBeanName); scanner.setResourceLoader(this .applicationContext); scanner.setBeanNameGenerator(this .nameGenerator); scanner.registerFilters(); scanner.scan(StringUtils.tokenizeToStringArray(this .basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); }
参考链接
参考链接