这是ApplicationContext的继承结构,我们可以发现ApplicationContext主要继承了三大重要接口:分别是beanFactory,resourceLoder,ApplicationEventPublisher,上两节讲了beanfactory,在这一节我想说一下resourceLoder与ApplicationEventPublisher,
resourceLoder
我们首先看一下它的顶级接口defaultResourceLoader
@Override
public Resource getResource(String location) {
if(location.startsWith(CLASSPATH_URL_PREFIX)){
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()));
}else {
try{
URL url=new URL(location);
return new URLResource(url);
} catch (MalformedURLException e) {
return new FileSystemResource(location);
}
}
}
它可以解析三种不同的文件地址并将其转化为Resource,所解析的resource文件最终被resourceReader解析
public void loadBeanDefinitions(Resource resource) throws BeansException {
try {
InputStream inputStream=resource.getInputStream();
try {
doLoadBeanDefinitions(inputStream);
}finally {
inputStream.close();
}
} catch (IOException | DocumentException e) {
throw new BeansException("IOException parsing XML document from " + resource, e);
}
}
private void doLoadBeanDefinitions(InputStream inputStream) throws DocumentException {
SAXReader reader=new SAXReader();
Document document=reader.read(inputStream);
Element root=document.getRootElement();
Element componentScan =root.element(COMPONENT_SCAN_ELEMENT);
if(componentScan!=null){
String scanPath=componentScan.attributeValue(BASE_PACKAGE_ATTRIBUTE);
if (StrUtil.isEmpty(scanPath)){
throw new BeansException("The value of base-package attribute can not be empty or null");
}
scanPackage(scanPath);
}
List<Element>beanList=root.elements(BEAN_ELEMENT);
for(Element bean:beanList){
String beanId = bean.attributeValue(ID_ATTRIBUTE);
String beanName = bean.attributeValue(NAME_ATTRIBUTE);
String className = bean.attributeValue(CLASS_ATTRIBUTE);
String initMethodName = bean.attributeValue(INIT_METHOD_ATTRIBUTE);
String destroyMethodName = bean.attributeValue(DESTROY_METHOD_ATTRIBUTE);
String beanScope = bean.attributeValue(SCOPE_ATTRIBUTE);
String lazyInit = bean.attributeValue(LAZYINIT_ATTRIBUTE);
Class<?> clazz;
try {
clazz =Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
beanName=StrUtil.isEmpty(beanId)?beanName:beanId;
if(StrUtil.isEmpty(beanName)){
beanName=StrUtil.lowerFirst(clazz.getSimpleName());
}
BeanDefinition beanDefinition=new BeanDefinition(clazz);
beanDefinition.setInitMethodName(initMethodName);
beanDefinition.setDestroyMethodName(destroyMethodName);
beanDefinition.setLazyInit(Boolean.parseBoolean(lazyInit));
if (StrUtil.isNotEmpty(beanScope)) {
beanDefinition.setScope(beanScope);
}
List<Element>propertyList=bean.elements(PROPERTY_ELEMENT);
for(Element property: propertyList){
String propertyNameAttribute=property.attributeValue(NAME_ATTRIBUTE);
String propertyValueAttribute=property.attributeValue(VALUE_ATTRIBUTE);
String propertyRefAttribute=property.attributeValue(REF_ATTRIBUTE);
if(StrUtil.isEmpty(propertyNameAttribute)){
throw new BeansException("The name attribute cannot be null");
}
Object value=propertyValueAttribute;
if (StrUtil.isNotEmpty(propertyRefAttribute)) {
value = new BeanReference(propertyRefAttribute);
}
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(propertyNameAttribute,value));
}
if(getRegistry().containsBeanDefinition(beanName)){
throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
}
getRegistry().registerBeanDefinition(beanName,beanDefinition);
}
}
我们可以看到,它里面组合了BeanDefinitionRegister,ResourceLoader,可以将文件(特别是xml文件来解析成BeanDefinition)(通过Document树实现逐层解析的)。
ApplicationEventPublisher
这是spring实现消息传递的方式,首先有一个消息多发者
@Override
public void multicastEvent(ApplicationEvent event) {
for(ApplicationListener<ApplicationEvent>applicationListener:applicationListeners){
if(supportsEvent(applicationListener,event)){
applicationListener.onApplicationEvent(event);
}
}
}
private boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {
Type type =applicationListener.getClass().getGenericInterfaces()[0];
Type actualTypeArgument = ((ParameterizedType) type).getActualTypeArguments()[0];
String typeName = actualTypeArgument.getTypeName();
Class<?>eventClassName;
try {
eventClassName =Class.forName(typeName);
}catch (ClassNotFoundException e){
throw new BeansException("wrong event class name: " + typeName);
}
return eventClassName.isAssignableFrom(event.getClass());
}
每当受到一个event,它都会遍历beanFactory里的applicationListeners,通过反射来看这ApplicationListener里的event泛型(一定要继承ApplicationEvent)是否是接收到的event类或其父类,如果是,就通过钩子方法来调用applicationListener.onApplicationEvent(event);