网上写spring的文章多如牛毛,为何还要写呢,由于,很简单,那是人家写的;网上都鼓励你不要造轮子,为何你还要造呢,由于,那不是你造的。java
我不是要造spring,我只是想把本身学习spring的一些感想,一些心得说出来,但愿你们看到有不对的地方,请必定不吝赐教。git
说说我本身,13年小本毕业,软件工程专业,校招去了最近疯传的牢厂
总部里待了2年,15年越狱
出来,某落魄互联网公司(PC时代风头无两)待了1年,慨叹深圳买房之艰难,遂于16年末回蓉。趁着热血未冷,去了一家创业公司,9个月后,欠薪3月,靠刷信用卡还贷,不得不含泪辞职;17年投奔国企,目前从事公共安全相关工做,趁着对技术还有一腔热情,没事写写文章,目前主要兴趣是:分布式、微服务等后端技术;对k8s等新技术保持关注;没事参加一些线下技术活动,欢迎你们和我交流。github
原本,我是想分享一些 spring cloud 的东西,但后来发现,我本身在读spring cloud的过程当中,有些东西也不是理解得很透彻,好比各类@Enable注解实际上是用到了spring boot的东西,而后我以为应该倒回去先看看spring boot,而后呢,看spring boot的过程当中,发现spring 和 spring boot实际上是一个深度融合,“你中有我,我中有你”的关系,好比spring boot启动时,不是会连带启动spring 容器吗,等等。spring
我就想着,干脆把spring boot系统研究一把算了,我在github上找了spring boot的工程,克隆到了码云上(速度要快得多),而后本身回退到了spring boot的第一个版本,时间大概是2013年4月,其实这第一个版本,基本的代码也已经成型了,我就拿这个版本的源码在本地idea里面看,配套的spring 版本是4.0.0,也还行。bootstrap
我本身加了很多注释在工程里,工程地址在这:后端
https://gitee.com/ckl111/spring-boot-first-version-learnapi
工程结构以下:安全
这个工程我也会一直维护着,我以为,spring 4.0.0的版本,暂时对我阅读代码来讲,足够了,若是你们大概了解spring 每一个版本的新特性的话,能够发现,spring 4.0开始,各类注解已经很完善了,如今虽然已经出到5.2版本了,但核心的东西也仍是没有变化,因此,对咱们研读源码,影响不大。若是真的把这个版本能读得差很少了,那想必对spring /spring boot的核心也理解差很少了,到时候再读新版本的源码也不迟,是吧。app
整体来讲:框架
spring boot 版本,2013年4月,first version。
配套的spring版本,4.0.0.BOOTSTRAP-SNAPSHOT
那时候的spring boot长什么样子,我这边给个地址(我这已经克隆到码云了)
https://gitee.com/ckl111/spring-boot/tree/fb6b2244707dd5dfad12d62cb6a3c396555270d1/
由于我这个系列,大概会按照思惟导图的流程来走,而后思惟导图太大了,我这里先直接贴前面这部分:
思惟导图完整连接:https://www.processon.com/view/link/5deeefdee4b0e2c298aa5596
我大概的讲解思路也会是上面那样,从上到下,每一个点细细地讲。
闲言少叙,进入正题。第一讲,先说说bean definition吧,这个东西,实在过重要了,核心的存储结构啊。
你们能够再想想,spring 当初刚出来的时候,主打的是ioc容器,容器里装了啥呢,bean啊!bean是什么呢?
恩。。。我也不知道是啥,反正spring里拿出来的就是bean。
行,那bean有什么特征吗?
哦,bean是一个对象,有名字,有class类型,有scope(单例、prototype那些),有role(属于应用的bean、仍是spring框架的bean),有是否延迟初始化(lazy-init),有它依赖的其余bean,若是这个bean很差造(不能直接反射生成的话),可能还有个工厂方法和工厂bean呢,哎,好像还说漏了,反正挺多的。
那是否是每一个bean都有这些属性呢?
仔细想一想,好像是的吧。
既然都有这些东西,那这个东西感受像是个模板了,就像是最近写了年终总结,hr小姐姐就给咱们发了模板,上面姓名啊、部门啊、职位啊、述职的基本格式啊,都是固定的,咱们只要拿来,填上本身的信息就好了,那咱们是否是能够抽象一下,搞个class啊,好比下面这样:
package com.learn; import lombok.Data; @Data public class SpringDefinition { /** * bean class名 */ String beanClassName; /** * 工厂bean的名称 */ String factoryBeanName; /** * 工厂方法的名称 */ String factoryMethodName; /** * singleton/prototype等 */ String scope; /** * 是否延迟初始化 */ boolean isLazyInit; /** * 依赖的bean */ String[] dependsOn; /** * bean的角色,好比:1:框架;2:应用 */ int role; /** * 是否为主候选bean */ boolean primary; ...其余属性 }
实话说,是能够的,一些简单的,轻量级ioc容器就是这么玩的,可是spring做为优秀代码的表明,确定不能这么low,接口的抽象性要好得多,方便咱们替换不一样的实现,该用接口来抽象,确定要抽象为接口。
下边咱们就看看该接口,先看接口的描述:
* A BeanDefinition describes a bean instance, which has property values, * constructor argument values, and further information supplied by * concrete implementations. * * <p>This is just a minimal interface: The main intention is to allow a * {@link BeanFactoryPostProcessor} such as {@link PropertyPlaceholderConfigurer} * to introspect and modify property values and other bean metadata. * @author Juergen Hoeller * @author Rob Harrop * @since 19.03.2004
这里说的是,bean definition描述一个bean实例的各类属性,尤为声明了:这是一个最小化接口,主要目的是容许bean factory后置处理器,对bean property和其余元数据进行修改。并且,这是2004年的接口,可想而知,是多么核心的api了。
再看看具体定义的方法,更好理解:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { /** * Return the name of the parent definition of this bean definition, if any. */ String getParentName(); /** * Set the name of the parent definition of this bean definition, if any. */ void setParentName(String parentName); /** * Return the current bean class name of this bean definition. * <p>Note that this does not have to be the actual class name used at runtime, in * case of a child definition overriding/inheriting the class name from its parent. * Hence, do <i>not</i> consider this to be the definitive bean type at runtime but * rather only use it for parsing purposes at the individual bean definition level. */ String getBeanClassName(); /** * Override the bean class name of this bean definition. * <p>The class name can be modified during bean factory post-processing, * typically replacing the original class name with a parsed variant of it. */ void setBeanClassName(String beanClassName); /** * Return the factory bean name, if any. */ String getFactoryBeanName(); /** * Specify the factory bean to use, if any. */ void setFactoryBeanName(String factoryBeanName); /** * Return a factory method, if any. */ String getFactoryMethodName(); /** * Specify a factory method, if any. This method will be invoked with * constructor arguments, or with no arguments if none are specified. * The method will be invoked on the specified factory bean, if any, * or otherwise as a static method on the local bean class. * @param factoryMethodName static factory method name, * or {@code null} if normal constructor creation should be used * @see #getBeanClassName() */ void setFactoryMethodName(String factoryMethodName); /** * Return the name of the current target scope for this bean, * or {@code null} if not known yet. */ String getScope(); /** * Override the target scope of this bean, specifying a new scope name. * @see #SCOPE_SINGLETON * @see #SCOPE_PROTOTYPE */ void setScope(String scope); /** * Return whether this bean should be lazily initialized, i.e. not * eagerly instantiated on startup. Only applicable to a singleton bean. */ boolean isLazyInit(); /** * Set whether this bean should be lazily initialized. * <p>If {@code false}, the bean will get instantiated on startup by bean * factories that perform eager initialization of singletons. */ void setLazyInit(boolean lazyInit); /** * Return the bean names that this bean depends on. */ String[] getDependsOn(); /** * Set the names of the beans that this bean depends on being initialized. * The bean factory will guarantee that these beans get initialized first. */ void setDependsOn(String[] dependsOn); /** * Return whether this bean is a candidate for getting autowired into some other bean. */ boolean isAutowireCandidate(); /** * Set whether this bean is a candidate for getting autowired into some other bean. */ void setAutowireCandidate(boolean autowireCandidate); /** * Return whether this bean is a primary autowire candidate. * If this value is true for exactly one bean among multiple * matching candidates, it will serve as a tie-breaker. */ boolean isPrimary(); /** * Set whether this bean is a primary autowire candidate. * <p>If this value is true for exactly one bean among multiple * matching candidates, it will serve as a tie-breaker. */ void setPrimary(boolean primary); /** * Return the constructor argument values for this bean. * <p>The returned instance can be modified during bean factory post-processing. * @return the ConstructorArgumentValues object (never {@code null}) */ ConstructorArgumentValues getConstructorArgumentValues(); /** * Return the property values to be applied to a new instance of the bean. * <p>The returned instance can be modified during bean factory post-processing. * @return the MutablePropertyValues object (never {@code null}) */ MutablePropertyValues getPropertyValues(); /** * Return whether this a <b>Singleton</b>, with a single, shared instance * returned on all calls. * @see #SCOPE_SINGLETON */ boolean isSingleton(); /** * Return whether this a <b>Prototype</b>, with an independent instance * returned for each call. * @see #SCOPE_PROTOTYPE */ boolean isPrototype(); /** * Return whether this bean is "abstract", that is, not meant to be instantiated. */ boolean isAbstract(); /** * Get the role hint for this {@code BeanDefinition}. The role hint * provides tools with an indication of the importance of a particular * {@code BeanDefinition}. * @see #ROLE_APPLICATION * @see #ROLE_INFRASTRUCTURE * @see #ROLE_SUPPORT */ int getRole(); /** * Return a human-readable description of this bean definition. */ String getDescription(); /** * Return a description of the resource that this bean definition * came from (for the purpose of showing context in case of errors). */ String getResourceDescription(); /** * Return the originating BeanDefinition, or {@code null} if none. * Allows for retrieving the decorated bean definition, if any. * <p>Note that this method returns the immediate originator. Iterate through the * originator chain to find the original BeanDefinition as defined by the user. */ BeanDefinition getOriginatingBeanDefinition(); }
你们仔细看看,是否是其实和咱们定义的class差很少呢,主要都是一些get/set方法。里面的字段呢,下一讲咱们详细讲解一下,会结合一些融会贯通的地方。
而后咱们看看这个接口有哪些实现吧?
能够看到,这里有两个是我标红了,由于他们特殊,特殊在他们不属于spring-beans包,而是在spring-context包里。后边遇到了咱们再单说,这里存疑。
再来看看这个接口的继承图:
咱们看到,这个接口有一个子接口,是AnnotatedBeanDefinition
。这个接口定义以下:
/** * Extended {@link org.springframework.beans.factory.config.BeanDefinition} * interface that exposes {@link org.springframework.core.type.AnnotationMetadata} * about its bean class - without requiring the class to be loaded yet. * 这个接口扩展了BeanDefinition,能够得到bean definition中的bean class上的注解元数据。 * 举个例子,假设咱们用@controller标注了某个类,那这里就能获取到@controller这个注解里面的信息 * * @author Juergen Hoeller * @since 2.5 * @see AnnotatedGenericBeanDefinition * @see org.springframework.core.type.AnnotationMetadata */ public interface AnnotatedBeanDefinition extends BeanDefinition { /** * Obtain the annotation metadata (as well as basic class metadata) * for this bean definition's bean class. * @return the annotation metadata object (never {@code null}) */ AnnotationMetadata getMetadata(); }
能够想想有什么用,这个接口能取到bean definition中对应bean class上标注的注解元数据。
好比下面的controller举例:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Controller { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any */ String value() default ""; }
那这个AnnotatedBeanDefinition
就能取到controller中的value字段的值。
我这里也写了个简单的例子,以下:
@Component("testService") public class HelloWorldService { }
@Autowired private ApplicationContext applicationContext; @Override public void run(String... args) { DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory(); // 获取bean definition,而后获取其注解元数据 AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanFactory.getBeanDefinition("testService"); AnnotationMetadata metadata = annotatedBeanDefinition.getMetadata(); Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes("org.springframework.stereotype.Component"); log.info("annotationAttributes:{}",annotationAttributes); }
我这边打印出来就是:
信息: annotationAttributes:{value=testService}
代码在
仔细看了两个接口 AnnotatedBeanDefinition
和BeanDefinition
,其实实现类都是差很少那几个。
基本上org.springframework.beans.factory.support.AbstractBeanDefinition
充当了基本的实现,基本上,该实现的方法都实现了,除了一个:
/** * Clone this bean definition. * To be implemented by concrete subclasses. * @return the cloned bean definition object */ public abstract AbstractBeanDefinition cloneBeanDefinition();
赶忙这个方法,对咱们分析也没多大帮助,暂时跳过便可。
再看看org.springframework.beans.factory.support.GenericBeanDefinition
,感受很重要,咱们看看:
public class GenericBeanDefinition extends AbstractBeanDefinition { private String parentName; /** * 这里有点意思,相似于builder模式,先生成一个实例,再本身各类set方法设置相关属性 * * Create a new GenericBeanDefinition, to be configured through its bean * properties and configuration methods. * @see #setBeanClass * @see #setBeanClassName * @see #setScope * @see #setAutowireMode * @see #setDependencyCheck * @see #setConstructorArgumentValues * @see #setPropertyValues */ public GenericBeanDefinition() { super(); } ... @Override public AbstractBeanDefinition cloneBeanDefinition() { return new GenericBeanDefinition(this); } }
ok,都这么简单的话,就再看两个,spring beans包中的org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition
:
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition { private final AnnotationMetadata metadata; /** * Create a new AnnotatedGenericBeanDefinition for the given bean class. * @param beanClass the loaded bean class */ public AnnotatedGenericBeanDefinition(Class<?> beanClass) { setBeanClass(beanClass); this.metadata = new StandardAnnotationMetadata(beanClass, true); } /** * Create a new AnnotatedGenericBeanDefinition for the given annotation metadata, * allowing for ASM-based processing and avoidance of early loading of the bean class. * Note that this constructor is functionally equivalent to * {@link org.springframework.context.annotation.ScannedGenericBeanDefinition * ScannedGenericBeanDefinition}, however the semantics of the latter indicate that * a bean was discovered specifically via component-scanning as opposed to other * means. * @param metadata the annotation metadata for the bean class in question * @since 3.1.1 */ public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) { Assert.notNull(metadata, "AnnotationMetadata must not be null"); setBeanClassName(metadata.getClassName()); this.metadata = metadata; } public final AnnotationMetadata getMetadata() { return this.metadata; } }
很简单,就是多了获取bean class的注解的功能。
再看这个呢,
/** * Extension of the {@link GenericBeanDefinition} * class, based on an ASM ClassReader, with support for annotation metadata exposed * through the {@link AnnotatedBeanDefinition} interface. * * <p>This class does <i>not</i> load the bean {@code Class} early. * It rather retrieves all relevant metadata from the ".class" file itself, * parsed with the ASM ClassReader. It is functionally equivalent to * {@link AnnotatedGenericBeanDefinition#AnnotatedGenericBeanDefinition(AnnotationMetadata)} * but distinguishes by type beans that have been <em>scanned</em> vs those that have * been otherwise registered or detected by other means. * * @author Juergen Hoeller * @author Chris Beams * @since 2.5 * @see #getMetadata() * @see #getBeanClassName() * @see org.springframework.core.type.classreading.MetadataReaderFactory * @see AnnotatedGenericBeanDefinition */ @SuppressWarnings("serial") public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition { private final AnnotationMetadata metadata; /** * Create a new ScannedGenericBeanDefinition for the class that the * given MetadataReader describes. * @param metadataReader the MetadataReader for the scanned target class */ public ScannedGenericBeanDefinition(MetadataReader metadataReader) { Assert.notNull(metadataReader, "MetadataReader must not be null"); this.metadata = metadataReader.getAnnotationMetadata(); setBeanClassName(this.metadata.getClassName()); } public final AnnotationMetadata getMetadata() { return this.metadata; } }
我一开始,一眼看过去,感受眼花了,差很少啊,但这个是在spring context包里,而后,能够看上面的注释,说是使用asm去获取注解信息。因此,这个和上面那个的差异是:
org.springframework.context.annotation.ScannedGenericBeanDefinition 位于spring-context,使用asm
org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition 位于spring-beans,使用反射
再看看org.springframework.beans.factory.support.RootBeanDefinition
(位于spring-beans),这个类下面只有一个子类,位于spring-context的
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.ConfigurationClassBeanDefinition
这两个类,一看就比较特别,能看出来,和@configuration注解有莫大关系,这个咱们放后面讲。
本篇就先到这里,留了一些问题,放到后面(有些我也要查一下,哈哈)。下一讲继续。