@ -0,0 +1,246 @@
|
||||
# Spring initApplicationEventMulticaster
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [huifer-spring](https://github.com/huifer/spring-framework-read)
|
||||
|
||||
|
||||
|
||||
## demo
|
||||
|
||||
```java
|
||||
package com.huifer.source.spring.applicationListener;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
|
||||
public class DemoApplicationListener implements ApplicationListener {
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
System.out.println("com.huifer.source.spring.applicationListener.DemoApplicationListener.onApplicationEvent");
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
```XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/beans"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<bean id="demoApplicationListener" class="com.huifer.source.spring.applicationListener.DemoApplicationListener"/>
|
||||
</beans>
|
||||
```
|
||||
|
||||
|
||||
|
||||
```JAVA
|
||||
public class ListenerSourceCode {
|
||||
public static void main(String[] args) {
|
||||
ApplicationContext context = new ClassPathXmlApplicationContext("Listener-demo.xml");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 初始化入口
|
||||
- `org.springframework.context.support.AbstractApplicationContext.refresh`中的`initApplicationEventMulticaster`方法
|
||||
|
||||
|
||||
|
||||
```java
|
||||
protected void initApplicationEventMulticaster() {
|
||||
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
|
||||
// 判断是否存在名字applicationEventMulticaster的bean
|
||||
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
|
||||
this.applicationEventMulticaster =
|
||||
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 创建一个
|
||||
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
|
||||
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
|
||||
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 注册
|
||||
|
||||
```JAVA
|
||||
protected void registerListeners() {
|
||||
// Register statically specified listeners first.
|
||||
// 读取 ApplicationListener
|
||||
for (ApplicationListener<?> listener : getApplicationListeners()) {
|
||||
getApplicationEventMulticaster().addApplicationListener(listener);
|
||||
}
|
||||
|
||||
// Do not initialize FactoryBeans here: We need to leave all regular beans
|
||||
// uninitialized to let post-processors apply to them!
|
||||
/**
|
||||
* 寻找类型为{@link ApplicationListener} 的beanName,目标文件为用户配置文件
|
||||
*/
|
||||
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
|
||||
for (String listenerBeanName : listenerBeanNames) {
|
||||
/**
|
||||
* 1. 获取 {@link applicationEventMulticaster}
|
||||
* 2. 添加监听器名称
|
||||
*/
|
||||
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
|
||||
}
|
||||
|
||||
// Publish early application events now that we finally have a multicaster...
|
||||
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
|
||||
this.earlyApplicationEvents = null;
|
||||
if (earlyEventsToProcess != null) {
|
||||
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
|
||||
getApplicationEventMulticaster().multicastEvent(earlyEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
![image-20200119163638222](/images/spring/image-20200119163638222.png)
|
||||
|
||||
|
||||
|
||||
## finishRefresh 发布
|
||||
|
||||
```java
|
||||
protected void finishRefresh() {
|
||||
// Clear context-level resource caches (such as ASM metadata from scanning).
|
||||
clearResourceCaches();
|
||||
|
||||
// Initialize lifecycle processor for this context.
|
||||
initLifecycleProcessor();
|
||||
|
||||
// Propagate refresh to lifecycle processor first.
|
||||
getLifecycleProcessor().onRefresh();
|
||||
|
||||
// Publish the final event.
|
||||
// 发布事件做处理
|
||||
publishEvent(new ContextRefreshedEvent(this));
|
||||
|
||||
// Participate in LiveBeansView MBean, if active.
|
||||
LiveBeansView.registerApplicationContext(this);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- `org.springframework.context.support.AbstractApplicationContext#publishEvent(org.springframework.context.ApplicationEvent)`
|
||||
- `org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```java
|
||||
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
|
||||
Assert.notNull(event, "Event must not be null");
|
||||
|
||||
// Decorate event as an ApplicationEvent if necessary
|
||||
ApplicationEvent applicationEvent;
|
||||
if (event instanceof ApplicationEvent) {
|
||||
applicationEvent = (ApplicationEvent) event;
|
||||
}
|
||||
else {
|
||||
applicationEvent = new PayloadApplicationEvent<>(this, event);
|
||||
if (eventType == null) {
|
||||
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
|
||||
}
|
||||
}
|
||||
|
||||
// Multicast right now if possible - or lazily once the multicaster is initialized
|
||||
if (this.earlyApplicationEvents != null) {
|
||||
this.earlyApplicationEvents.add(applicationEvent);
|
||||
}
|
||||
else {
|
||||
/**
|
||||
* 执行监听事件
|
||||
* {@link ApplicationEventMulticaster} ->{@link SimpleApplicationEventMulticaster}
|
||||
*/
|
||||
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
|
||||
}
|
||||
|
||||
// Publish event via parent context as well...
|
||||
if (this.parent != null) {
|
||||
if (this.parent instanceof AbstractApplicationContext) {
|
||||
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
|
||||
}
|
||||
else {
|
||||
this.parent.publishEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
- 执行监听方法
|
||||
|
||||
![image-20200119164149650](/images/spring/image-20200119164149650.png)
|
||||
|
||||
|
||||
|
||||
```java
|
||||
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
|
||||
ErrorHandler errorHandler = getErrorHandler();
|
||||
if (errorHandler != null) {
|
||||
try {
|
||||
doInvokeListener(listener, event);
|
||||
}
|
||||
catch (Throwable err) {
|
||||
errorHandler.handleError(err);
|
||||
}
|
||||
}
|
||||
else {
|
||||
doInvokeListener(listener, event);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
```java
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
|
||||
try {
|
||||
// 最后调用方法
|
||||
listener.onApplicationEvent(event);
|
||||
}
|
||||
catch (ClassCastException ex) {
|
||||
String msg = ex.getMessage();
|
||||
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
|
||||
// Possibly a lambda-defined listener which we could not resolve the generic event type for
|
||||
// -> let's suppress the exception and just log a debug message.
|
||||
Log logger = LogFactory.getLog(getClass());
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Non-matching event type for listener: " + listener, ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
![image-20200119164402137](/images/spring/image-20200119164402137.png)
|
||||
|
||||
![image-20200119164410301](/images/spring/image-20200119164410301.png)
|
@ -0,0 +1,403 @@
|
||||
# Spring 自定义属性解析器
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [huifer-spring](https://github.com/huifer/spring-framework-read)
|
||||
|
||||
## 用例
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/beans"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
|
||||
<property name="propertyEditorRegistrars">
|
||||
<list>
|
||||
<bean class="com.huifer.source.spring.bean.DatePropertyRegister"/>
|
||||
</list>
|
||||
</property>
|
||||
|
||||
<property name="customEditors">
|
||||
<map>
|
||||
<entry key="java.util.Date" value="com.huifer.source.spring.bean.DatePropertyEditor">
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="apple" class="com.huifer.source.spring.bean.Apple">
|
||||
<property name="date" value="2020-01-01 01:01:01"/>
|
||||
</bean>
|
||||
</beans>
|
||||
```
|
||||
|
||||
```java
|
||||
public class DatePropertyRegister implements PropertyEditorRegistrar {
|
||||
@Override
|
||||
public void registerCustomEditors(PropertyEditorRegistry registry) {
|
||||
registry.registerCustomEditor(Date.class, new CustomDateEditor(
|
||||
new SimpleDateFormat("yyyy-MM-dd"), true)
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
public class DatePropertyEditor extends PropertyEditorSupport {
|
||||
private String format = "yyyy-MM-dd";
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
System.out.println(text);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(format);
|
||||
try {
|
||||
Date date = sdf.parse(text);
|
||||
this.setValue(date);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## PropertyEditorRegistrar解析
|
||||
- 直接在`DatePropertyRegister`打上断点进行查看注册流程
|
||||
|
||||
![image-20200117104710142](/images/spring/image-20200117104710142.png)
|
||||
|
||||
直接看调用堆栈获取调用层次
|
||||
|
||||
```java
|
||||
@Override
|
||||
public void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor) {
|
||||
registerCustomEditor(requiredType, null, propertyEditor);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
```java
|
||||
@Override
|
||||
public void registerCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor) {
|
||||
if (requiredType == null && propertyPath == null) {
|
||||
throw new IllegalArgumentException("Either requiredType or propertyPath is required");
|
||||
}
|
||||
if (propertyPath != null) {
|
||||
if (this.customEditorsForPath == null) {
|
||||
this.customEditorsForPath = new LinkedHashMap<>(16);
|
||||
}
|
||||
this.customEditorsForPath.put(propertyPath, new CustomEditorHolder(propertyEditor, requiredType));
|
||||
}
|
||||
else {
|
||||
if (this.customEditors == null) {
|
||||
this.customEditors = new LinkedHashMap<>(16);
|
||||
}
|
||||
// 放入 customEditors map对象中
|
||||
this.customEditors.put(requiredType, propertyEditor);
|
||||
this.customEditorCache = null;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- `PropertyEditorRegistrySupport`
|
||||
|
||||
![image-20200117111131406](/images/spring/image-20200117111131406.png)
|
||||
|
||||
此处对象是通过`DatePropertyRegister`传递的
|
||||
|
||||
- `org.springframework.beans.factory.support.AbstractBeanFactory#registerCustomEditors`
|
||||
|
||||
```java
|
||||
protected void registerCustomEditors(PropertyEditorRegistry registry) {
|
||||
PropertyEditorRegistrySupport registrySupport =
|
||||
(registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null);
|
||||
if (registrySupport != null) {
|
||||
registrySupport.useConfigValueEditors();
|
||||
}
|
||||
if (!this.propertyEditorRegistrars.isEmpty()) {
|
||||
for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) {
|
||||
try {
|
||||
/**
|
||||
* {@link ResourceEditorRegistrar#registerCustomEditors(org.springframework.beans.PropertyEditorRegistry)}或者
|
||||
* {@link PropertyEditorRegistrar#registerCustomEditors(org.springframework.beans.PropertyEditorRegistry)}
|
||||
*/
|
||||
registrar.registerCustomEditors(registry);
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
Throwable rootCause = ex.getMostSpecificCause();
|
||||
if (rootCause instanceof BeanCurrentlyInCreationException) {
|
||||
BeanCreationException bce = (BeanCreationException) rootCause;
|
||||
String bceBeanName = bce.getBeanName();
|
||||
if (bceBeanName != null && isCurrentlyInCreation(bceBeanName)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() +
|
||||
"] failed because it tried to obtain currently created bean '" +
|
||||
ex.getBeanName() + "': " + ex.getMessage());
|
||||
}
|
||||
onSuppressedException(ex);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this.customEditors.isEmpty()) {
|
||||
this.customEditors.forEach((requiredType, editorClass) ->
|
||||
registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass)));
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- `void registerCustomEditors(PropertyEditorRegistry registry);` 用例中编写的`DatePropertyRegister`正好有这个方法的实现
|
||||
|
||||
·
|
||||
|
||||
- 在`AbstractBeanFactory`中查看变量
|
||||
|
||||
![image-20200117110115741](/images/spring/image-20200117110115741.png)
|
||||
|
||||
|
||||
|
||||
- 为什么最后结果变成`com.huifer.source.spring.bean.DatePropertyEditor`
|
||||
|
||||
看配置文件
|
||||
|
||||
```xml
|
||||
<property name="customEditors">
|
||||
<map>
|
||||
<entry key="java.util.Date" value="com.huifer.source.spring.bean.DatePropertyEditor">
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
|
||||
```
|
||||
|
||||
- 对应的set方法
|
||||
|
||||
```java
|
||||
public void setCustomEditors(Map<Class<?>, Class<? extends PropertyEditor>> customEditors) {
|
||||
this.customEditors = customEditors;
|
||||
}
|
||||
```
|
||||
|
||||
![image-20200117110846256](/images/spring/image-20200117110846256.png)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## applyPropertyValues
|
||||
|
||||
- 应用属性值
|
||||
|
||||
|
||||
|
||||
```java
|
||||
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
|
||||
if (pvs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
|
||||
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
|
||||
}
|
||||
|
||||
MutablePropertyValues mpvs = null;
|
||||
// 没有解析的属性
|
||||
List<PropertyValue> original;
|
||||
|
||||
if (pvs instanceof MutablePropertyValues) {
|
||||
mpvs = (MutablePropertyValues) pvs;
|
||||
if (mpvs.isConverted()) {
|
||||
//MutablePropertyValues 对象中存在转换后对象直接赋值
|
||||
// Shortcut: use the pre-converted values as-is.
|
||||
try {
|
||||
bw.setPropertyValues(mpvs);
|
||||
return;
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new BeanCreationException(
|
||||
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
|
||||
}
|
||||
}
|
||||
original = mpvs.getPropertyValueList();
|
||||
}
|
||||
else {
|
||||
original = Arrays.asList(pvs.getPropertyValues());
|
||||
}
|
||||
// 自定义转换器
|
||||
TypeConverter converter = getCustomTypeConverter();
|
||||
if (converter == null) {
|
||||
converter = bw;
|
||||
}
|
||||
// 创建BeanDefinitionValueResolver
|
||||
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
|
||||
|
||||
// Create a deep copy, resolving any references for values.
|
||||
// 解析后的对象集合
|
||||
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
|
||||
boolean resolveNecessary = false;
|
||||
for (PropertyValue pv : original) {
|
||||
// 解析过的属性
|
||||
if (pv.isConverted()) {
|
||||
deepCopy.add(pv);
|
||||
}
|
||||
// 没有解析过的属性
|
||||
else {
|
||||
// 属性名称
|
||||
String propertyName = pv.getName();
|
||||
// 属性值,直接读取到的
|
||||
Object originalValue = pv.getValue();
|
||||
// 解析值
|
||||
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
|
||||
Object convertedValue = resolvedValue;
|
||||
/**
|
||||
* 1. isWritableProperty: 属性可写
|
||||
* 2. isNestedOrIndexedProperty: 是否循环嵌套
|
||||
*/
|
||||
boolean convertible = bw.isWritableProperty(propertyName) &&
|
||||
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
|
||||
if (convertible) {
|
||||
// 转换器解析
|
||||
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
|
||||
}
|
||||
// Possibly store converted value in merged bean definition,
|
||||
// in order to avoid re-conversion for every created bean instance.
|
||||
if (resolvedValue == originalValue) {
|
||||
if (convertible) {
|
||||
// 设置解析值
|
||||
pv.setConvertedValue(convertedValue);
|
||||
}
|
||||
deepCopy.add(pv);
|
||||
}
|
||||
// 类型解析
|
||||
else if (convertible && originalValue instanceof TypedStringValue &&
|
||||
!((TypedStringValue) originalValue).isDynamic() &&
|
||||
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
|
||||
pv.setConvertedValue(convertedValue);
|
||||
deepCopy.add(pv);
|
||||
}
|
||||
else {
|
||||
resolveNecessary = true;
|
||||
deepCopy.add(new PropertyValue(pv, convertedValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mpvs != null && !resolveNecessary) {
|
||||
// 转换成功的标记方法
|
||||
mpvs.setConverted();
|
||||
}
|
||||
|
||||
// Set our (possibly massaged) deep copy.
|
||||
try {
|
||||
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
throw new BeanCreationException(
|
||||
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
![image-20200117133325461](/images/spring/image-20200117133325461.png)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
![image-20200117141309038](/images/spring/image-20200117141309038.png)
|
||||
|
||||
|
||||
|
||||
![image-20200117141519123](/images/spring/image-20200117141519123.png)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- 属性值解析
|
||||
|
||||
![image-20200117142800671](/images/spring/image-20200117142800671.png)
|
||||
|
||||
```JAVA
|
||||
@Nullable
|
||||
private Object convertForProperty(
|
||||
@Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
|
||||
|
||||
if (converter instanceof BeanWrapperImpl) {
|
||||
return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
|
||||
}
|
||||
else {
|
||||
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
|
||||
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
|
||||
return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
```JAVA
|
||||
private Object doConvertTextValue(@Nullable Object oldValue, String newTextValue, PropertyEditor editor) {
|
||||
try {
|
||||
editor.setValue(oldValue);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("PropertyEditor [" + editor.getClass().getName() + "] does not support setValue call", ex);
|
||||
}
|
||||
// Swallow and proceed.
|
||||
}
|
||||
// 调用子类实现方法
|
||||
editor.setAsText(newTextValue);
|
||||
return editor.getValue();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
- 调用用例编写的方法
|
||||
|
||||
```JAVA
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
System.out.println(text);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(format);
|
||||
try {
|
||||
Date date = sdf.parse(text);
|
||||
this.setValue(date);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
![image-20200117143022827](/images/spring/image-20200117143022827.png)
|
||||
|
||||
该值也是这个方法的返回`org.springframework.beans.TypeConverterDelegate#convertIfNecessary(java.lang.String, java.lang.Object, java.lang.Object, java.lang.Class<T>, org.springframework.core.convert.TypeDescriptor)`
|
||||
|
@ -0,0 +1,210 @@
|
||||
# Spring MessageSource
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [huifer-spring](https://github.com/huifer/spring-framework-read)
|
||||
|
||||
## 初始化入口
|
||||
- `org.springframework.context.support.AbstractApplicationContext.refresh`方法有`initMessageSource()`方法进行了`MessageSource`初始化
|
||||
|
||||
|
||||
|
||||
```java
|
||||
protected void initMessageSource() {
|
||||
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
|
||||
// 判断是否含有 messageSource
|
||||
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
|
||||
// 读取xml配置文件中 id="messageSource"的数据
|
||||
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
|
||||
// Make MessageSource aware of parent MessageSource.
|
||||
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
|
||||
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
|
||||
if (hms.getParentMessageSource() == null) {
|
||||
// Only set parent context as parent MessageSource if no parent MessageSource
|
||||
// registered already.
|
||||
hms.setParentMessageSource(getInternalParentMessageSource());
|
||||
}
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Using MessageSource [" + this.messageSource + "]");
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Use empty MessageSource to be able to accept getMessage calls.
|
||||
// 没有使用默认的 DelegatingMessageSource
|
||||
DelegatingMessageSource dms = new DelegatingMessageSource();
|
||||
dms.setParentMessageSource(getInternalParentMessageSource());
|
||||
this.messageSource = dms;
|
||||
// 注册单例对象
|
||||
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
读取xml配置文件
|
||||
|
||||
![image-20200119141937915](/images/spring/image-20200119141937915.png)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## getMessage
|
||||
|
||||
- `org.springframework.context.support.AbstractApplicationContext#getMessage(java.lang.String, java.lang.Object[], java.util.Locale)`
|
||||
|
||||
```java
|
||||
@Override
|
||||
public String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
|
||||
return getMessageSource().getMessage(code, args, locale);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- `org.springframework.context.support.AbstractMessageSource#getMessage(java.lang.String, java.lang.Object[], java.util.Locale)`
|
||||
|
||||
```java
|
||||
@Override
|
||||
public final String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
|
||||
// 获取对应的信息
|
||||
String msg = getMessageInternal(code, args, locale);
|
||||
if (msg != null) {
|
||||
return msg;
|
||||
}
|
||||
// 默认信息 null
|
||||
String fallback = getDefaultMessage(code);
|
||||
if (fallback != null) {
|
||||
return fallback;
|
||||
}
|
||||
throw new NoSuchMessageException(code, locale);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- 两个方法
|
||||
|
||||
1. `org.springframework.context.support.AbstractMessageSource#getDefaultMessage(java.lang.String)`
|
||||
|
||||
```java
|
||||
@Nullable
|
||||
protected String getDefaultMessage(String code) {
|
||||
// 判断是否使用默认值
|
||||
if (isUseCodeAsDefaultMessage()) {
|
||||
return code;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- 返回code本身或者`null`
|
||||
|
||||
2. `org.springframework.context.support.AbstractMessageSource#getMessageInternal`
|
||||
|
||||
```JAVA
|
||||
@Nullable
|
||||
protected String getMessageInternal(@Nullable String code, @Nullable Object[] args, @Nullable Locale locale) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
if (locale == null) {
|
||||
// 获取语言默认值
|
||||
locale = Locale.getDefault();
|
||||
}
|
||||
Object[] argsToUse = args;
|
||||
|
||||
if (!isAlwaysUseMessageFormat() && ObjectUtils.isEmpty(args)) {
|
||||
// Optimized resolution: no arguments to apply,
|
||||
// therefore no MessageFormat needs to be involved.
|
||||
// Note that the default implementation still uses MessageFormat;
|
||||
// this can be overridden in specific subclasses.
|
||||
String message = resolveCodeWithoutArguments(code, locale);
|
||||
if (message != null) {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
// Resolve arguments eagerly, for the case where the message
|
||||
// is defined in a parent MessageSource but resolvable arguments
|
||||
// are defined in the child MessageSource.
|
||||
argsToUse = resolveArguments(args, locale);
|
||||
|
||||
MessageFormat messageFormat = resolveCode(code, locale);
|
||||
if (messageFormat != null) {
|
||||
synchronized (messageFormat) {
|
||||
return messageFormat.format(argsToUse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check locale-independent common messages for the given message code.
|
||||
Properties commonMessages = getCommonMessages();
|
||||
if (commonMessages != null) {
|
||||
String commonMessage = commonMessages.getProperty(code);
|
||||
if (commonMessage != null) {
|
||||
return formatMessage(commonMessage, args, locale);
|
||||
}
|
||||
}
|
||||
|
||||
// Not found -> check parent, if any.
|
||||
return getMessageFromParent(code, argsToUse, locale);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
- `org.springframework.context.support.ResourceBundleMessageSource#resolveCodeWithoutArguments`
|
||||
|
||||
```JAVA
|
||||
@Override
|
||||
protected String resolveCodeWithoutArguments(String code, Locale locale) {
|
||||
Set<String> basenames = getBasenameSet();
|
||||
for (String basename : basenames) {
|
||||
// 加载 basename
|
||||
ResourceBundle bundle = getResourceBundle(basename, locale);
|
||||
if (bundle != null) {
|
||||
// 从basename对应的文件中获取对应的值
|
||||
String result = getStringOrNull(bundle, code);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
![image-20200119143046066](/images/spring/image-20200119143046066.png)
|
||||
|
||||
|
||||
|
||||
- 加载后截图
|
||||
|
||||
获取方法`String result = getStringOrNull(bundle, code);`就是map获取
|
||||
|
||||
![image-20200119144019171](/images/spring/image-20200119144019171.png)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- 没有配置文件的情况
|
||||
|
||||
![image-20200119145138205](/images/spring/image-20200119145138205.png)
|
@ -0,0 +1,62 @@
|
||||
# Spring OrderUtils
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [huifer-spring](https://github.com/huifer/spring-framework-read)
|
||||
- `org.springframework.core.annotation.OrderUtils`主要方法如下
|
||||
1. getOrder
|
||||
1. getPriority
|
||||
|
||||
- 测试类`org.springframework.core.annotation.OrderUtilsTests`
|
||||
|
||||
```java
|
||||
@Nullable
|
||||
public static Integer getOrder(Class<?> type) {
|
||||
// 缓存中获取
|
||||
Object cached = orderCache.get(type);
|
||||
if (cached != null) {
|
||||
// 返回 int
|
||||
return (cached instanceof Integer ? (Integer) cached : null);
|
||||
}
|
||||
/**
|
||||
* 注解工具类,寻找{@link Order}注解
|
||||
*/
|
||||
Order order = AnnotationUtils.findAnnotation(type, Order.class);
|
||||
Integer result;
|
||||
if (order != null) {
|
||||
// 返回
|
||||
result = order.value();
|
||||
} else {
|
||||
result = getPriority(type);
|
||||
}
|
||||
// key: 类名,value: intValue
|
||||
orderCache.put(type, (result != null ? result : NOT_ANNOTATED));
|
||||
return result;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
```java
|
||||
@Nullable
|
||||
public static Integer getPriority(Class<?> type) {
|
||||
if (priorityAnnotationType == null) {
|
||||
return null;
|
||||
}
|
||||
// 缓存中获取
|
||||
Object cached = priorityCache.get(type);
|
||||
if (cached != null) {
|
||||
// 不为空返回
|
||||
return (cached instanceof Integer ? (Integer) cached : null);
|
||||
}
|
||||
// 注解工具获取注解
|
||||
Annotation priority = AnnotationUtils.findAnnotation(type, priorityAnnotationType);
|
||||
Integer result = null;
|
||||
if (priority != null) {
|
||||
// 获取 value
|
||||
result = (Integer) AnnotationUtils.getValue(priority);
|
||||
}
|
||||
// 向缓存插入数据
|
||||
priorityCache.put(type, (result != null ? result : NOT_ANNOTATED));
|
||||
return result;
|
||||
}
|
||||
|
||||
```
|
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 24 KiB |