0%

Java-基础知识点整理4

Java异常分类和处理

Java注解

  • @Target

    表示这个注解使用的范围

  • @Retention

    表示这个注解的存活时间范围。比方说是

    作者:RednaxelaFX

    链接:https://www.zhihu.com/question/60835139/answer/180750670

    来源:知乎

    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    RetentionPolicy.SOURCE:只在本编译单元的编译过程中保留,并不写入Class文件中。这种注解主要用于在本编译单元(这里一个Java源码文件可以看作一个编译单元)内触发注解处理器(annotation processor)的相关处理,例如说可以让注解处理器相应地生成一些代码,或者是让注解处理器做一些额外的类型检查(@Override),等等。

    RetentionPolicy.CLASS:在编译的过程中保留并且会写入Class文件中,但是JVM在加载类的时候不需要将其加载为运行时可见的(反射可见)的注解。这里很重要的一点是编译多个Java文件时的情况:假如要编译A.java源码文件和B.class文件,其中A类依赖B类,并且B类上有些注解希望让A.java编译时能看到,那么B.class里就必须要持有这些注解信息才行。

    • 同时我们可能不需要让它在运行时对反射可见(例如说为了减少运行时元数据的大小之类),所以会选择CLASS而不是RUNTIME。

    RetentionPolicy.RUNTIME:在编译过程中保留,会写入Class文件,并且JVM加载类的时候也会将其加载为反射可见的注解。这就不用多说了,例如说Spring的依赖注入就会在运行时通过扫描类上的注解来决定注入啥。

  • @Document

    描述javadoc

  • @Inherited

    如果值是是的话 被标注了这个注解的类的子类也会有这个注解

Spring 原理

Spring Bean 生命周期

生命周期

生命周期

生命周期

Bean的定义

可以通过在xml中定义Bean

1
2
3
4
5
6
<beans>
<bean id = "" class = "">
<property name="name" value="root"/>
<property name="password" value="${jdbc.password]}"
</bean>
</beans>

或者在类上面使用@Component的注解。 通过ComponentScan的方式要找到相关的类。插一句 ComponentScan的怎么做

  • ComponentScanAnnotationParser#parse

  • ClassPathBeanDefinitionScanner#doScan

  • ClassPathScanningCandidateComponentProvider#findCandidateComponents

    ​ 要做的事情就是读取Class的文件流,通过JVM中class的定义获得实现的接口等的信息,然后把这些信息写入到beandefinition 对象中。

    • 将class path 中的.替换成/

    • 拼装成 classpath:经过转换的basePackage地址 + **/\.class

    • MetadataReaderFactory#getMetadataReader

    • SimpleMetadataReader#getMetadataReader

    • ClassReader#accept

      这里涉及到ASM的内容ASM4使用指南 根据规范编译后的class文件的格式是固定的,我们可以根据ASM工具来从class文件中读取我们关心的信息。

    返回含有父类、实现接口、注解等信息的包装类(RootBeanDefination)

从DefaultListableBeanFactory 管中窥豹 看Bean的生命流程

因为BeanFactory是懒加载的 ,当我们调用getBean()的时候,会

  • AbstractBeanFactory#doGetBean(inal String name, final Class requiredType, final Object[] args, boolean typeCheckOnly)

    • transformedBeanName

      得到bean Name,入参的beanName中如果有&符号 截取到最后一个&开始到结束的子字符串作为bean name

    • DefaultSingletonBeanRegistry#getSingleton

      背景知识 Bean的循环依赖和解决

      以下内容来自 Spring-bean的循环依赖以及解决方式

      Spring的单例对象的初始化主要分为三步:

      • create Bean Instance 实例化

      • popluate Bean 填充属性

      • Initalize Bean 初始化

        在Spring容器整个生命周期内,有且只有一个对象,所以很容易想到这个对象应该存在Cache中,Spring为了解决单例的循环依赖问题,使用了三级缓存

        DefaultSingletonBeanRegistry.class

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        /** Cache of singleton objects: bean name --> bean instance */
        // 单例对象的cache
        private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

        /** Cache of singleton factories: bean name --> ObjectFactory */
        // 单例工厂的cache
        private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

        /** Cache of early singleton objects: bean name --> bean instance */
        // 提前曝光的单例对象
        private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

        尝试从cache中获得对象

        DefaultSingletonBeanRegistry#getSingleton

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) {
        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
        if (singletonFactory != null) {
        singletonObject = singletonFactory.getObject();
        this.earlySingletonObjects.put(beanName, singletonObject);
        this.singletonFactories.remove(beanName);
        }
        }
        }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
        }

        上面的代码需要解释两个参数:

        isSingletonCurrentlyInCreation()判断当前单例bean是否正在创建中,也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象, 或则在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。)
        allowEarlyReference 是否允许从singletonFactories中通过getObject拿到对象
        分析getSingleton()的整个过程,Spring首先从一级缓存singletonObjects中获取。如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取。如果还是获取不到且允许singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取,如果获取到了则:

        1
        2
        this.earlySingletonObjects.put(beanName, singletonObject);
        this.singletonFactories.remove(beanName);
 从singletonFactories中移除,并放入earlySingletonObjects中。其实也就是从三级缓存移动到了二级缓存。

 从上面三级缓存的分析,我们可以知道,Spring解决循环依赖的诀窍就在于singletonFactories这个三级cache。这个cache的类型是ObjectFactory,定义如下:

 
1
2
3
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
这个接口在下面被引用
1
2
3
4
5
6
7
8
9
10
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (! this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
这里就是解决循环依赖的关键,这段代码发生在createBeanInstance之后,也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),所以Spring此时将这个对象提前曝光出来让大家认识,让大家使用。 这样做有什么好处呢?让我们来分析一下“A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”这种循环依赖的情况。A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中。此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化。 知道了这个原理时候,肯定就知道为啥Spring不能解决“A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象”这类问题了!因为加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决。 参考 http://www.jianshu.com/p/6c359768b1dc 如果在三级缓存中找到了 再通过BeanName做一次判断 判断这个 我们想要的是这个bean 还是生成这个bean的factory。 在最初的时候我们是把bean name 给处理了一次的 看上面的**transformedBeanName** 说明。
  • getObjectForBeanInstance

    在之前我们在cache中找到了bean。但是这个bean可能是factoryBean。 我们需要通过工厂Bean 获得产品Bean

    AbstractBeanFactory#getObjectForBeanInstance

    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
    protected Object getObjectForBeanInstance(
    Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

    // Don't let calling code try to dereference the factory if the bean isn't a factory.
    // 因为在尝试获得bean的使用bean的名字是去掉&符号的。&表示工厂bean。 但是根据这个beanName获取道的并不是FactoryBean的 抛错
    if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
    throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
    }

    // Now we have the bean instance, which may be a normal bean or a FactoryBean.
    // If it's a FactoryBean, we use it to create a bean instance, unless the
    // caller actually wants a reference to the factory.
    // 相当于 ! beanInstance instanceof FactoryBean && ! BeanFactoryUtils.isFactoryDereference(name) 确定 名字并不是BeanFactory类型的 且 得到的类并不是工厂类型的, return bean
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
    return beanInstance;
    }
    // 否则就是通过BeanFactory构建Bean
    Object object = null;
    if (mbd == null) {
    object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
    // Return bean instance from factory.
    FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
    // Caches object obtained from FactoryBean if it is a singleton.
    if (mbd == null && containsBeanDefinition(beanName)) {
    mbd = getMergedLocalBeanDefinition(beanName);
    }
    boolean synthetic = (mbd != null && mbd.isSynthetic());
    object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
    }

    通过getObjectFromFactoryBean获得Bean,在factoryBeanObjectCache中是不是已经存在Bean了,如果存在直接返回, 如果没有 通过BeanFactory 构建,构建的Bean还是要AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization 进行组装。 同时根据factory bean 是否是isSingleton的来确定是否要加入到factoryBeanObjectCache中

    FactoryBeanRegistrySupport#getObjectFromFactoryBean

    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
    52
    53
    54
    55
    56
    57
    58
    59
    60
    /**
    * Obtain an object to expose from the given FactoryBean.
    * @param factory the FactoryBean instance
    * @param beanName the name of the bean
    * @param shouldPostProcess whether the bean is subject to post-processing
    * @return the object obtained from the FactoryBean
    * @throws BeanCreationException if FactoryBean object creation failed
    * @see org.springframework.beans.factory.FactoryBean#getObject()
    */
    protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    if (factory.isSingleton() && containsSingleton(beanName)) {
    synchronized (getSingletonMutex()) {
    Object object = this.factoryBeanObjectCache.get(beanName);
    if (object == null) {
    object = doGetObjectFromFactoryBean(factory, beanName);
    // Only post-process and store if not put there already during getObject() call above
    // (e.g. because of circular reference processing triggered by custom getBean calls)
    Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
    if (alreadyThere != null) {
    object = alreadyThere;
    }
    else {
    if (object != null && shouldPostProcess) {
    if (isSingletonCurrentlyInCreation(beanName)) {
    // Temporarily return non-post-processed object, not storing it yet..
    return object;
    }
    beforeSingletonCreation(beanName);
    try {
    object = postProcessObjectFromFactoryBean(object, beanName);
    }
    catch (Throwable ex) {
    throw new BeanCreationException(beanName,
    "Post-processing of FactoryBean's singleton object failed", ex);
    }
    finally {
    afterSingletonCreation(beanName);
    }
    }
    if (containsSingleton(beanName)) {
    this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
    }
    }
    }
    return (object != NULL_OBJECT ? object : null);
    }
    }
    else {
    Object object = doGetObjectFromFactoryBean(factory, beanName);
    if (object != null && shouldPostProcess) {
    try {
    object = postProcessObjectFromFactoryBean(object, beanName);
    }
    catch (Throwable ex) {
    throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
    }
    }
    return object;
    }
    }
  • 如果这个Bean在这之前没有创建过,那么要进行创建。

    • 如果这个Beanfactroy有parent Bean factory的话。 那么通过委托的方式看能不能得到bean

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      // Check if bean definition exists in this factory.
      BeanFactory parentBeanFactory = getParentBeanFactory();
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
      // Not found -> check parent.
      String nameToLookup = originalBeanName(name);
      if (args != null) {
      // Delegation to parent with explicit args.
      return (T) parentBeanFactory.getBean(nameToLookup, args);
      }
      else {
      // No args -> delegate to standard getBean method.
      return parentBeanFactory.getBean(nameToLookup, requiredType);
      }
      }
      • 保证创建这个bean的时候,它构造方法中的Bean都已经创建好了

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        String[] dependsOn = mbd.getDependsOn();
        if (dependsOn != null) {
        for (String dep : dependsOn) {
        if (isDependent(beanName, dep)) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
        }
        registerDependentBean(dep, beanName);
        try {
        getBean(dep);
        }
        catch (NoSuchBeanDefinitionException ex) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
        }
        }
        }
      • DefaultSingletonBeanRegistry#isDependent

        通过递归的方式进行调用 保证这个Bean 构造方法中所依赖的Bean,Bean 构造方法中所依赖的Bean的构造方法中(如果这个Bean还没有被创建的话)所依赖的Bean… 都已经准备好了,否则报错💥

        *这里就显示了通过构造方法,依赖注入的方式创建Bean,Bean之间不允许互相依赖,但是通过setter的方式,依赖注入Bean, Bean之间是允许 *

        特别说明

        举个简单例子:例如 B 依赖了 A,则 dependentBeanMap 缓存中应该存放一对映射:其中 key 为 A,value 为含有 B 的 Set;而 dependenciesForBeanMap 缓存中也应该存放一对映射:其中 key 为:B,value 为含有 A 的 Set。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
              private boolean isDependent(String beanName, String dependentBeanName, Set<String> alreadySeen) {
        if (alreadySeen != null && alreadySeen.contains(beanName)) {
        return false;
        }
        String canonicalName = canonicalName(beanName);
        Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
        if (dependentBeans == null) {
        return false;
        }
        if (dependentBeans.contains(dependentBeanName)) {
        return true;
        }
        for (String transitiveDependency : dependentBeans) {
        if (alreadySeen == null) {
        alreadySeen = new HashSet<String>();
        }
        alreadySeen.add(beanName);
        if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
        return true;
        }
        }
        return false;
        }
  1. BeanFactoryPostProcessor

    将${}中的值做替换成*.properties中的内容

  2. InstantiationAwareBeanPostProcessor#postProcessBeforInstantiation

    Instantiation [ɪnstænʃɪ’eɪʃən]

    执行Bean的构造器

  3. InstantiationAwareBeanPostProcessor#postProcessPropertyValue

    根据xml中的定义设置property的值

  4. ApplicationContextAwareProcessor#postProcessBeforeInitialization

    ApplicationContextAwareProcessor是BeanPostProcessor的一个实现 在内部会调用invokeAwareInterfaces方法 里面会有很多的if 来判断这个类是不是特定的aware类型,比方说

1
2
3
if (object instanceof ApplicationContextAware) {
((ApplicationContextAware) object).setApplicationContext();
}