您的位置:首页 > 编程语言 > Java开发

【Spring】揭开Spring朦胧的面纱

2016-07-23 16:19 344 查看
使用Spring的IOC容器获取一个Bean的实质,其实可以简化成使用反射的一个过程。

首先

这是一个Bean的定义。

Student bean

package cn.edu.au.selection.service;

public class Student {

private String name;

private int age;

public Student() {
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}


然后

启动Spring的时候,也就是Spring初始化的时候。有经验的人都知道ApplicationContext的初始化过程主要是在
AbstractApplicationContext
类中
refresh()
方法中进行。而且该方法中最重要的两个子方法分别是
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
finishBeanFactoryInitialization(beanFactory);


第一个方法

第一个方法的主要作用就是创建可供上下文使用的基本IOC容器,也就是
DefaultListableBeanFactory
。由该IOC容器对我们所注册的
BeanDefinition
以及Bean进行托管。在该IOC容器的初始化过程中,主要做了三件事:

1. `BeanDefinition`的`Resource`的定位。也就是说我们配置`<bean></bean>`标签的Spring`*.xml`文件的定位。或是`FileSystemResource`,或是`ClassPathContextResource`。这些Resource其实就是对Xml文件的一个封装。
2. 当定位到`Resource`之后,便可以解析 `BeanDefinition`了。该`BeanDefinition`其实是对Bean定义的一个抽象。包含你定义的Bean的一些元数据、`ClassLoader`等等。该过程又可能分成两个步骤,第一步,进行Xml文件解析,该步只是将文件当成普通的Xml文件进行解析。而第二步就是Spring按照`<bean></bean>`标签的定义对`BeanDefinition`进行解析生成`BeanDefinition`对象。这个对象由`AbstractBeanDefinition`指向,放在IOC容器中统一托管。
3. 第三步就是`BeanDefination`在IoC容器中的注册,也就是正式托管的过程。这个过程其实就是将`BeanDefination`放入`DefaultListableBeanFactory`的一个`ConcurrentHashMap`中,叫做`beanDefinitionMap`。供随后创建Bean的实体做准备。


注意:在第二个步骤中,不仅仅将
*.xml
文件中定义的Bean的
BeanDefinition
解析出来,而且将有
<context:component-scan/>
标签的,有
@Component
等注解的那些Bean的
BeanDefinition
也解析出来。当然还有Spring内部自己使用的一些Bean的
BeanDefinition


第二个方法

第二个方法
finishBeanFactoryInitialization(beanFactory);
的主要作用就是初始化所有剩余的非延迟加载
(non-lazy-init)
的单例的Bean。注意,在这个方法的调用栈中就包含了我们会使用的
ApplicationContext.getBean()
的调用。也就是说,其实所有Bean的创建都是在
getBean()
方法中进行的。方法调用中有一个比较关键的方法就是
AbstractBeanFactory.doGetBean()
方法。这个方法的逻辑路线是这样的。

首先当初始化上下文的时候,非延迟加载的单例Bean先会通过
Object sharedInstance = getSingleton(beanName);
方法查找。当使用
getBean
方法的时候,首先也是在
getSingleton(beanName)
方法中查找有没有之前创建好的实例。这一步如果没有找到,当然只能找到单例,prototype类型的肯定找不到,还有
lazy-init
的也会找不到。

然后进行一个判断。首先从IOC容器中获取
BeanDefination
,从其中判断待获取的Bean是单例还是原型
(prototype)
模式。如果是原型模式,每次创建一个Bean的实例即可。如果是单例模式,当第一次创建完实例之后需要保存到IOC容器中,第二次获取的时候就无需再次创建了。同样的,该单例Bean也是保存在
DefaultListableBeanFactory
的另一个
ConcurrentHashMap
中,叫做
singletonObjects


在创建Bean实例,调用
AbstractAutowiredCapableBeanFactory.doCreateBean()
方法时有两个关键的方法,分别是
createBeanInstance()
populateBean()
。其中第一个方法就是使用反射,调用类的构造方法来创建一个该类的实例对象。而第二个方法就是对该实例对象进行初始化,也就是实例中属性的初始化。有些
@Autowired
或者
@Value
的注解的属性的初始化都会在这里进行。并且有
@Autowired
注解的属性还会触发递归调用创建Bean的方法。说白了,就是依赖关系处理的过程。

在完成依赖关系处理之后,在该方法中接着会执行一个这个方法
initializeBean()
,这个方法中又有三个重要的方法,分别是
applyBeanPostProcessorsBeforeInitialization()
invokeInitMethods()
applyBeanPostProcessorsAfterInitialization()
。其中含有
@PostConstruct
注解的方法会在第一个方法中执行。第二个方法中一般执行
BeanDefinition
中指定的
init-method
方法或者
afterPropertitiesSet()
实现方法。

创建Bean实例的简化过程

至此,Spring之IOC容器的初始化过程以及依赖注入都说完了。

那么创建Bean实例的过程可以简化成以下代码:

package cn.edu.au.selection.service;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Reflection {

private static Logger logger = LoggerFactory.getLogger(Reflection.class);

public static void main(String[] args){
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
Class<?> clazz;
String className = "cn.edu.au.selection.service.Student";
Object object = null;
String name = "Ethan Hunt";
int age = 18;
try {
clazz = classLoader.loadClass(className);
Constructor<?>[] ctors = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : ctors){
constructor.setAccessible(true);
object = constructor.newInstance();
}
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(object, name);
Method method = clazz.getDeclaredMethod("setAge", int.class);
method.setAccessible(true);
method.invoke(object, age);

} catch (ClassNotFoundException e) {
logger.error("class {} cannot be found!", className);
e.printStackTrace();
} catch (InvocationTargetException e) {
logger.error("被调用的方法{}的内部抛出了异常而没有被捕获!", "Student()/setAge()");
e.printStackTrace();
} catch (InstantiationException e) {
logger.error("{}类无法被实例化!", className);
e.printStackTrace();
} catch (IllegalAccessException e) {
logger.error("方法{}或属性{}无法被访问!", "setAge()", "name");
e.printStackTrace();
} catch (NoSuchFieldException e) {
logger.error("没有这样的属性{}!", "name");
e.printStackTrace();
} catch (NoSuchMethodException e) {
logger.error("没有这样的方法{}!", "setAge()");
e.printStackTrace();
}
logger.info(JSON.toJSONString(object));
}
}


输出结果为:

{
"age": 18,
"name": "Ethan Hunt"
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息