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 | <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
17protected 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
2this.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
33protected 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
17String[] 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
23private 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;
}
BeanFactoryPostProcessor
将${}中的值做替换成*.properties中的内容
InstantiationAwareBeanPostProcessor#postProcessBeforInstantiation
Instantiation [ɪnstænʃɪ’eɪʃən]
执行Bean的构造器
InstantiationAwareBeanPostProcessor#postProcessPropertyValue
根据xml中的定义设置property的值
ApplicationContextAwareProcessor#postProcessBeforeInitialization
ApplicationContextAwareProcessor是BeanPostProcessor的一个实现 在内部会调用invokeAwareInterfaces方法 里面会有很多的if 来判断这个类是不是特定的aware类型,比方说
1 | if (object instanceof ApplicationContextAware) { |