接下来,再在看看AnnotatedBeanDefinition的三个子类:
ScannedGenericBeanDefinition:存储@Component、@Service、@Controller等注解注释的类
它的源码很简单,就是多了一个属性:private final AnnotationMetadata metadata用来存储扫描进来的Bean的一些注解信息。
// 实现了AnnotatedBeanDefinition 也继承了GenericBeanDefinition public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition { private final AnnotationMetadata metadata; ... // 它只有一个构造函数:必须传入MetadataReader public ScannedGenericBeanDefinition(MetadataReader metadataReader) { Assert.notNull(metadataReader, "MetadataReader must not be null"); this.metadata = metadataReader.getAnnotationMetadata(); setBeanClassName(this.metadata.getClassName()); } }
AnnotatedGenericBeanDefinition
在基于注解驱动的Spring应用着,它使用得非常的多。因为获取注解信息非常的方便~
AnnotatedGenericBeanDefinition只能用于已经被注册或被扫描到的类(否则你手动new一个,它就不在容器里了,那就脱离管理了)
使用案例:
public static void main(String[] args) { AnnotatedBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(RootConfig.class); // 就这么一下子,就把注解们都拿到了,简直不要太方便,简直可以当工具类来用 Set<String> annotationTypes = beanDefinition.getMetadata().getAnnotationTypes(); System.out.println(annotationTypes); //[org.springframework.context.annotation.ComponentScan, org.springframework.context.annotation.Configuration] System.out.println(beanDefinition.isSingleton()); //true System.out.println(beanDefinition.getBeanClassName()); //com.config.RootConfig }
源码参考;
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition { private final AnnotationMetadata metadata; @Nullable private MethodMetadata factoryMethodMetadata; /** * Create a new AnnotatedGenericBeanDefinition for the given bean class. * @param beanClass the loaded bean class 注意官方这个注释:已经加载进来了的Bean的Class */ public AnnotatedGenericBeanDefinition(Class<?> beanClass) { setBeanClass(beanClass); this.metadata = new StandardAnnotationMetadata(beanClass, true); } //@since 3.1.1 此处传入AnnotationMetadata ,也得保证对应的class已经被loaded public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) { Assert.notNull(metadata, "AnnotationMetadata must not be null"); if (metadata instanceof StandardAnnotationMetadata) { setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass()); } else { setBeanClassName(metadata.getClassName()); } this.metadata = metadata; } //@since 4.1.1 可以由指定的工厂方法产生这个Bean public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata, MethodMetadata factoryMethodMetadata) { this(metadata); Assert.notNull(factoryMethodMetadata, "MethodMetadata must not be null"); setFactoryMethodName(factoryMethodMetadata.getMethodName()); this.factoryMethodMetadata = factoryMethodMetadata; } @Override public final AnnotationMetadata getMetadata() { return this.metadata; } @Override @Nullable public final MethodMetadata getFactoryMethodMetadata() { return this.factoryMethodMetadata; } }
ConfigurationClassBeanDefinition
首先需要注意的是,它是ConfigurationClassBeanDefinitionReader的一个私有的静态内部类:这个类负责将@Bean注解的方法转换为对应的ConfigurationClassBeanDefinition类(非常的重要)
// 它直接继承自RootBeanDefinition private static class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition { ... 源码和之前的差得不是太多,此处就不解释了 }
它有一些默认的设置处理如下:
- 如果@Bean注解没有指定bean的名字,默认会用方法的名字命名bean
- @Configuration注解的类会成为一个工厂类,而所有的@Bean注解的方法会成为工厂方法,通过工厂方法实例化Bean,而不是直接通过构造函数初始化(所以我们方法体里面可以很方便的书写逻辑。。。)
Spring初始化时,会用GenericBeanDefinition或是ConfigurationClassBeanDefinition(用@Bean注解注释的类)存储用户自定义的Bean,在初始化Bean时,又会将其转换为RootBeanDefinition。
BeanDefinitionBuilder:快速创建一个Bean定义
使用它的好处是,可以进行方法的连缀。
没有特殊指明,创建的都是GenericBeanDefinition,源码非常的简单,下面只用个Deme看看即可
public class BeanDefinitionBuilder { //=================创建一个Builder 没特殊指明,都是GenericBeanDefinition public static BeanDefinitionBuilder genericBeanDefinition() { return new BeanDefinitionBuilder(new GenericBeanDefinition()); } .... public static BeanDefinitionBuilder rootBeanDefinition(String beanClassName) { return rootBeanDefinition(beanClassName, null); } public static BeanDefinitionBuilder childBeanDefinition(String parentName) { return new BeanDefinitionBuilder(new ChildBeanDefinition(parentName)); } }
demo:
public static void main(String[] args) { AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Child.class) .setRole(BeanDefinition.ROLE_APPLICATION) .setScope(BeanDefinition.SCOPE_SINGLETON) .addPropertyValue("name", "fsx") .setLazyInit(false) //Spring5.0后提供的,可以自己书写函数,在里面做任意事情 //bdf是个AbstractBeanDefinition .applyCustomizers((bdf) -> { AbstractBeanDefinition abdf = (AbstractBeanDefinition) bdf; abdf.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_NO); }).getRawBeanDefinition(); System.out.println(beanDefinition); //Generic bean: class [com.fsx.maintest.Child]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; d... }
BeanDefinitionReader:该接口的作用就是加载 Bean
在 Spring 中,Bean 一般来说都在配置文件中定义。而在配置的路径由在 web.xml 中定义(还有全注解的方式)。所以加载 Bean 的步骤大致就是:
1.加载资源,通过配置文件的路径(Location)加载配置文件(Resource)
2.解析资源,通过解析配置文件的内容得到 Bean。
public interface BeanDefinitionReader { // 得到Bean定义的register BeanDefinitionRegistry getRegistry(); // 返回用于加载资源的 ResourceLoader(可以为null) @Nullable ResourceLoader getResourceLoader(); // 加载Bean的类加载器 @Nullable ClassLoader getBeanClassLoader(); // 生成Bean名称的名字生成器(若没有指定名称的话,会调用它生成) BeanNameGenerator getBeanNameGenerator(); // 核心方法,loadbean定义进来,然后注册到上面的register 里面去 int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException; int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException; int loadBeanDefinitions(String location) throws BeanDefinitionStoreException; int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException; }
它的继承结构非常简单,一个抽象实现+3个具体实现
AbstractBeanDefinitionReader
它实现了一些基本的方法,但是核心方法loadBeanDefinitions
肯定是交给子类实现了
public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader { private final BeanDefinitionRegistry registry; @Nullable private ResourceLoader resourceLoader; @Nullable private ClassLoader beanClassLoader; // 会有环境变量 private Environment environment; // 默认的名字生成器(类名首字母小写) private BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator(); // 此构造函数,会完成一些参数的初始化 protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); this.registry = registry; // Determine ResourceLoader to use. if (this.registry instanceof ResourceLoader) { this.resourceLoader = (ResourceLoader) this.registry; } else { // 注意这个处理~~~~ this.resourceLoader = new PathMatchingResourcePatternResolver(); } // Inherit Environment if possible // 如果注册器里有环境变量,就用它的 否则new一个标准的~~~~ 它下面也提供了set方法可以设置 if (this.registry instanceof EnvironmentCapable) { this.environment = ((EnvironmentCapable) this.registry).getEnvironment(); } else { this.environment = new StandardEnvironment(); } } public void setEnvironment(Environment environment) { Assert.notNull(environment, "Environment must not be null"); this.environment = environment; } public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) { this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new DefaultBeanNameGenerator()); } ... }
XmlBeanDefinitionReader:从xml中加载Bean定义信息
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { ... }
我们注解配置中@Configuration上也可以加上@ImportResource导入外置的xml配置文件。它由此方法ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromImportedResources处理,内部借助的就是XmlBeanDefinitionReader去解析它的
PropertiesBeanDefinitionReader:直接从properties文件或者Map里加载Bean
由于它语法怪异,因此基本不适用了
GroovyBeanDefinitionReader:不在本文讨论中
可能有小伙伴问:那我们注解的@Bean以及@Component的这么些bean定义都是谁去加载的呢? 需要注意的是这个就不属于它了。
@Bean都是@Configuration配置类里,统一由ConfigurationClassParser#parse()里去处理的(直接执行Method就行)
@Component这种组件统一由解析@ComponentScan的处理器的ComponentScanAnnotationParser(借助ClassPathBeanDefinitionScanner) 参考博文:【小家Spring】Spring解析@ComponentScan注解源码分析(ComponentScanAnnotationParser、ClassPathBeanDefinitionScanner)
总结
本编文章旨在讲解贯穿Spring IoC容器上下文的Bean定义接口、实现类等等。从设计中我们能发现,Spring的设计原则还是非常优秀的,单一职责的特性。
宁愿用扩展的方法多写类,也不会在Base里面加内容变得臃肿最终几乎笨重不可维护
有了这些基础,相信你在看Spring源码的时候又能更加顺畅很多了~共勉
(RootBeanDefinition、AnnotatedGenericBeanDefinition)