Merge pull request #22 from huifer/master

Spring source code
pull/23/head
AmyliaY 5 years ago committed by GitHub
commit f13fa64ef7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -25,7 +25,7 @@
- [温习一下servlet](/docs/Spring/SpringMVC/温习一下servlet.md)
- [IoC 容器在 Web 环境中的启动](/docs/Spring/SpringMVC/IoC容器在Web环境中的启动.md)
- [SpringMVC 的设计与实现](/docs/Spring/SpringMVC/SpringMVC的设计与实现.md)
- [SpringMVC 跨域解析](/docs/Spring/SpringMVC/SpringMVC-CROS.md)
### SpringJDBC
@ -39,12 +39,15 @@
- [面筋哥 IoC 容器的一天(上)](/docs/Spring/Spring源码故事瞎编版/面筋哥IoC容器的一天(上).md)
### Spring 类解析
- [Spring 自定义标签解析](/docs/Spring/clazz/Spring-自定义标签解析.md)
- [Spring 自定义标签解析](/docs/Spring/clazz/Spring-Custom-label-resolution.md)
- [Spring Scan 包扫描](/docs/Spring/clazz/Spring-scan.md)
- [Spring 注解工具类](/docs/Spring/clazz/Spring-AnnotationUtils.md)
- [Spring 别名注册](/docs/Spring/clazz/Spring-SimpleAliasRegistry.md)
- [Spring 标签解析类](/docs/Spring/clazz/Spring-BeanDefinitionParserDelegate.md)
- [Spring ApplicationListener](/docs/Spring/clazz/Spring-ApplicationListener.md)
- [Spring messageSource](/docs/Spring/clazz/Spring-MessageSource.md)
- [Spring 自定义属性解析器](/docs/Spring/clazz/Spring-Custom-attribute-resolver.md)
- [Spring 排序工具](/docs/Spring/clazz/Spring-OrderUtils.md)
### Spring5 新特性
- [Spring5-spring.components解析](/docs/Spring/Spring5新特性/Spring-spring-components.md)

@ -1,658 +0,0 @@
# Spring 自定义标签解析
- Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [huifer-spring](https://github.com/huifer/spring-framework)
- 与自定义标签解析相关的类
1. `org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser`
2. `org.springframework.beans.factory.xml.NamespaceHandlerSupport`
- 开始源码之前先搭建一个环境
## 环境搭建
- 创建对象
```java
public class UserXtd {
private String userName;
private String emailAddress;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
}
```
- 创建 xsd 文件
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.huifer.com/schema/user"
elementFormDefault="qualified">
<element name="myUser">
<complexType>
<attribute name="id" type="string"/>
<attribute name="userName" type="string"/>
<attribute name="emailAddress" type="string"/>
</complexType>
</element>
</schema>
```
- 创建 namespaceHandler
```java
public class UserNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("myUser", new UserBeanDefinitionParser());
}
}
```
- 创建 beanDefinitionParser
```java
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
/**
* 标签对应class
* @param element the {@code Element} that is being parsed
* @return
*/
@Override
protected Class<?> getBeanClass(Element element) {
return UserXtd.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// 获取 userName 标签属性值
String name = element.getAttribute("userName");
// 获取 emailAddress 标签属性值
String address = element.getAttribute("emailAddress");
if (StringUtils.hasText(name)) {
builder.addPropertyValue("userName", name);
}
if (StringUtils.hasText(address)) {
builder.addPropertyValue("emailAddress", address);
}
}
}
```
- 创建 resource/META-INF/spring.handlers
```text
http\://www.huifer.com/schema/user=com.huifer.source.spring.parser.UserNamespaceHandler
```
- 创建 resource/META-INF/spring.schemas
```text
http\://www.huifer.com/schema/user.xsd=META-INF/spring-test.xsd
```
- 创建测试用例xml
```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:myname="http://www.huifer.com/schema/user"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.huifer.com/schema/user http://www.huifer.com/schema/user.xsd
">
<myname:myUser id="testUserBean" userName="huifer" emailAddress="huifer97@163.com"/>
</beans>
```
- 创建 Java 运行方法
```java
/**
* 自定义标签测试用例
*/
public class XSDDemo {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("XTD-xml.xml");
UserXtd user = (UserXtd) applicationContext.getBean("testUserBean");
System.out.println(user.getEmailAddress());
}
}
```
- 这里我们希望输出结果是`huifer97@163.com`,运行后结果也确实是`huifer97@163.com`
## 解析 DefaultNamespaceHandlerResolver
- 入口方法`org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions`
```java
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 不同标签的解析
parseDefaultElement(ele, delegate);
}
else {
// 非spring 默认标签解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
```
- 调用链路
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(org.w3c.dom.Element)`
- `org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)`
```java
/**
* Parse a custom element (outside of the default namespace).
* <p>
* 自定义标签解析
*
* @param ele the element to parse
* @param containingBd the containing bean definition (if any)
* @return the resulting bean definition
*/
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 自定义标签解析
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 根据命名空间获取处理类
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// 自定义处理器
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
```
![image-20200109084131415](/images/spring/image-20200109084131415.png)
- `http://www.huifer.com/schema/user`和我们定义的xsd文件中的url相同如何找到对应的NamespaceHandler,在`META-INF/spring.handlers`中有定义,
`http\://www.huifer.com/schema/user=com.huifer.source.spring.parser.UserNamespaceHandler`
`NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);`这行代码就是获取`spring.handlers`中的定义
- 处理方法`org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolve`
```java
/**
* Locate the {@link NamespaceHandler} for the supplied namespace URI
* from the configured mappings.
*
* 根据 namespaceUri 获取对应的 {@link NamespaceHandler}
* @param namespaceUri the relevant namespace URI
* @return the located {@link NamespaceHandler}, or {@code null} if none found
*/
@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
// 获取handlerMapping
Map<String, Object> handlerMappings = getHandlerMappings();
// 从 handlerMapping 中获取类名
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
// 判断是否处理过,处理过直接返回
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
// 没有处理,进行反射还原类
String className = (String) handlerOrClassName;
try {
// 通过反射还原类
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
// 初始化类
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
// 调用init()方法,自定义类中实现
namespaceHandler.init();
// 放入缓存
handlerMappings.put(namespaceUri, namespaceHandler);
// 返回自定义的 namespaceHandler
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
"] for namespace [" + namespaceUri + "]", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
className + "] for namespace [" + namespaceUri + "]", err);
}
}
}
```
- `org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#getHandlerMappings`跟踪这个方法
```JAVA
/**
* Load the specified NamespaceHandler mappings lazily.
*
* 获取handlerMappings
*/
private Map<String, Object> getHandlerMappings() {
Map<String, Object> handlerMappings = this.handlerMappings;
}
```
![image-20200109085606240](/images/spring/image-20200109085606240.png)
- 这里直接存在数据了,他是从什么时候加载的?
- `org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions`
这个方法在注册bean定义的时候调用
```java
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
// 注册方法
// createReaderContext 初始化HandlerMapping
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
```
- 继续跟踪`createReaderContext`
```java
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#createReaderContext
```
```java
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
```
- 继续跟踪`getNamespaceHandlerResolver`
`org.springframework.beans.factory.xml.XmlBeanDefinitionReader#getNamespaceHandlerResolver`
```java
public NamespaceHandlerResolver getNamespaceHandlerResolver() {
if (this.namespaceHandlerResolver == null) {
this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
}
return this.namespaceHandlerResolver;
}
```
- 继续跟踪`createDefaultNamespaceHandlerResolver`
`org.springframework.beans.factory.xml.XmlBeanDefinitionReader#createDefaultNamespaceHandlerResolver`
```java
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader());
return new DefaultNamespaceHandlerResolver(cl);
}
```
- 继续跟踪`DefaultNamespaceHandlerResolver`
`org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver`
```java
public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) {
this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}
```
他回到了我们之前疑问的地方 `handlerMappings` 如何出现的
断点
![image-20200109090456547](/images/spring/image-20200109090456547.png)
```JAVA
public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) {
this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}
```
`public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";`
![image-20200109090655157](/images/spring/image-20200109090655157.png)
此时还是空
走完
![image-20200109091216505](/images/spring/image-20200109091216505.png)
```java
@Override
public String toString() {
return "NamespaceHandlerResolver using mappings " + getHandlerMappings();
}
```
```JAVA
/**
* Load the specified NamespaceHandler mappings lazily.
*
* 获取handlerMappings
*/
private Map<String, Object> getHandlerMappings() {
Map<String, Object> handlerMappings = this.handlerMappings;
// 缓存不存在
if (handlerMappings == null) {
synchronized (this) {
handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
if (logger.isTraceEnabled()) {
logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
}
try {
// 将本地文件读出
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isTraceEnabled()) {
logger.trace("Loaded NamespaceHandler mappings: " + mappings);
}
handlerMappings = new ConcurrentHashMap<>(mappings.size());
// 转换成map结构
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
this.handlerMappings = handlerMappings;
}
catch (IOException ex) {
throw new IllegalStateException(
"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
}
}
}
}
return handlerMappings;
}
```
![image-20200109094032421](/images/spring/image-20200109094032421.png)
## org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#resolve
```java
@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
// 获取handlerMapping
Map<String, Object> handlerMappings = getHandlerMappings();
// 从 handlerMapping 中获取类名
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
// 判断是否处理过,处理过直接返回
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
// 没有处理,进行反射还原类
String className = (String) handlerOrClassName;
try {
// 通过反射还原类
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
// 初始化类
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
// 调用init()方法,自定义类中实现
namespaceHandler.init();
// 放入缓存
handlerMappings.put(namespaceUri, namespaceHandler);
// 返回自定义的 namespaceHandler
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
"] for namespace [" + namespaceUri + "]", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
className + "] for namespace [" + namespaceUri + "]", err);
}
}
}
```
执行`init`方法
```java
public class UserNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("myUser", new UserBeanDefinitionParser());
}
}
```
```java
/**
* Subclasses can call this to register the supplied {@link BeanDefinitionParser} to
* handle the specified element. The element name is the local (non-namespace qualified)
* name.
*
* 将标签名称,标签解析类放入
*/
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
this.parsers.put(elementName, parser);
}
```
- 方法走完,回到开始的方法
```java
/**
* Parse a custom element (outside of the default namespace).
* <p>
* 自定义标签解析
*
* @param ele the element to parse
* @param containingBd the containing bean definition (if any)
* @return the resulting bean definition
*/
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 自定义标签解析
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 根据命名空间获取处理类
// org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolve
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// 自定义处理器
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
```
![image-20200109092801572](/images/spring/image-20200109092801572.png)
## org.springframework.beans.factory.xml.NamespaceHandler#parse
- `org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse`
```java
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionParser parser = findParserForElement(element, parserContext);
return (parser != null ? parser.parse(element, parserContext) : null);
}
```
### org.springframework.beans.factory.xml.NamespaceHandlerSupport#findParserForElement
```java
@Nullable
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
// 获取标签名称
String localName = parserContext.getDelegate().getLocalName(element);
// 在map中获取对应的标签解析类
BeanDefinitionParser parser = this.parsers.get(localName);
// 空报错
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
// 不为空返回
return parser;
}
```
![image-20200109093242494](/images/spring/image-20200109093242494.png)
### org.springframework.beans.factory.xml.BeanDefinitionParser#parse
- `org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parse`
```java
public final BeanDefinition parse(Element element, ParserContext parserContext) {
/**
* {@link AbstractSingleBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)}
*/
AbstractBeanDefinition definition = parseInternal(element, parserContext);
}
```
### org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#parseInternal
```java
@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
String parentName = getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}
// 调用自己实现的方法 com.huifer.source.spring.parser.UserBeanDefinitionParser.getBeanClass
Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
}
else {
// getBeanClassName 同样也是可以在自定义的解析类中实现
String beanClassName = getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
if (containingBd != null) {
// Inner bean definition must receive same scope as containing bean.
// 设置scope
builder.setScope(containingBd.getScope());
}
if (parserContext.isDefaultLazyInit()) {
// Default-lazy-init applies to custom bean definitions as well.
// 设置 lazy-init
builder.setLazyInit(true);
}
// 执行解析方法,在自定义解析类中存在com.huifer.source.spring.parser.UserBeanDefinitionParser.doParse
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
```
![image-20200109094654409](/images/spring/image-20200109094654409.png)
执行`com.huifer.source.spring.parser.UserBeanDefinitionParser#doParse`
```JAVA
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// 获取 userName 标签属性值
String name = element.getAttribute("userName");
// 获取 emailAddress 标签属性值
String address = element.getAttribute("emailAddress");
if (StringUtils.hasText(name)) {
builder.addPropertyValue("userName", name);
}
if (StringUtils.hasText(address)) {
builder.addPropertyValue("emailAddress", address);
}
}
```

@ -0,0 +1,615 @@
# Spring-MVC 跨域
## CrossOrigin注解
- 通过注解设置跨域 demo 如下
```java
package com.huifer.source.controller;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
@CrossOrigin(maxAge = 3600)
@RequestMapping("/")
@RestController
public class JSONController {
@ResponseBody
@GetMapping(value = "/json")
public Object ob() {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("1", "a");
return hashMap;
}
}
```
- 切入点:
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#registerHandlerMethod`
- `org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#register`方法
```java
/**
* 注册方法 将controller 相关信息存储
*
* @param mapping 请求地址
* @param handler 处理类
* @param method 函数
*/
public void register(T mapping, Object handler, Method method) {
// 上锁
this.readWriteLock.writeLock().lock();
try {
// 创建 HandlerMethod , 通过 handler 创建处理的对象(controller)
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
// 设置值
this.mappingLookup.put(mapping, handlerMethod);
// 获取url
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
// 设置
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
/**
* 跨域设置
* {@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#initCorsConfiguration(Object, Method, RequestMappingInfo)}
**/
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
// 开锁
this.readWriteLock.writeLock().unlock();
}
}
```
- 着重查看**`CorsConfiguration`**初始化方法
- `org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#initCorsConfiguration`
```JAVA
@Override
protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) {
// 重新创建,为什么不作为参数传递: 还有别的实现方法
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
// 获取bean
Class<?> beanType = handlerMethod.getBeanType();
// 获取注解信息
CrossOrigin typeAnnotation = AnnotatedElementUtils.findMergedAnnotation(beanType, CrossOrigin.class);
CrossOrigin methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class);
if (typeAnnotation == null && methodAnnotation == null) {
return null;
}
CorsConfiguration config = new CorsConfiguration();
// 更新跨域信息
updateCorsConfig(config, typeAnnotation);
updateCorsConfig(config, methodAnnotation);
if (CollectionUtils.isEmpty(config.getAllowedMethods())) {
for (RequestMethod allowedMethod : mappingInfo.getMethodsCondition().getMethods()) {
config.addAllowedMethod(allowedMethod.name());
}
}
// 返回跨域配置默认值
return config.applyPermitDefaultValues();
}
```
信息截图:
![image-20200123085741347](/images/springMVC/clazz/image-20200123085741347.png)
![image-20200123085756168](/images/springMVC/clazz/image-20200123085756168.png)
### updateCorsConfig
- 该方法对原有的配置信息做补充
```java
private void updateCorsConfig(CorsConfiguration config, @Nullable CrossOrigin annotation) {
if (annotation == null) {
return;
}
for (String origin : annotation.origins()) {
config.addAllowedOrigin(resolveCorsAnnotationValue(origin));
}
for (RequestMethod method : annotation.methods()) {
config.addAllowedMethod(method.name());
}
for (String header : annotation.allowedHeaders()) {
config.addAllowedHeader(resolveCorsAnnotationValue(header));
}
for (String header : annotation.exposedHeaders()) {
config.addExposedHeader(resolveCorsAnnotationValue(header));
}
String allowCredentials = resolveCorsAnnotationValue(annotation.allowCredentials());
if ("true".equalsIgnoreCase(allowCredentials)) {
config.setAllowCredentials(true);
}
else if ("false".equalsIgnoreCase(allowCredentials)) {
config.setAllowCredentials(false);
}
else if (!allowCredentials.isEmpty()) {
throw new IllegalStateException("@CrossOrigin's allowCredentials value must be \"true\", \"false\", " +
"or an empty string (\"\"): current value is [" + allowCredentials + "]");
}
if (annotation.maxAge() >= 0 && config.getMaxAge() == null) {
config.setMaxAge(annotation.maxAge());
}
}
```
最终解析结果
![image-20200123085946476](/images/springMVC/clazz/image-20200123085946476.png)
- 解析完成后放入 `corsLookup`对象中 类:**`org.springframework.web.servlet.handler.AbstractHandlerMethodMapping`**
```java
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
```
## xml 配置方式
```xml
<mvc:cors>
<mvc:mapping path="/**"
allowed-origins="http://domain1.com, http://domain2.com"
allowed-methods="GET, PUT"
allowed-headers="header1, header2, header3"
exposed-headers="header1, header2" allow-credentials="false"
max-age="3600" />
<mvc:mapping path="/**"
allowed-origins="http://domain1.com" />
</mvc:cors>
```
- `mvc`标签解析类: `org.springframework.web.servlet.config.MvcNamespaceHandler`这个类对Spring配置文件中的`<mvc:xxx>`标签做了解析设定,如这次我们的关注点**`CORS`**
```java
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
/**
* 初始化一些SpringMvc 的解析类
*/
@Override
public void init() {
// 注解驱动
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
// 默认的 servlet 处理器
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
// 拦截器
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
// 资源
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
// 视图控制器
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
// 重定向视图控制器
registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
// 视图解析器
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
// tiles 处理器
registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
// 跨域处理
registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
}
}
```
### CorsBeanDefinitionParser
#### 类图
![image-20200123090442409](/images/springMVC/clazz/image-20200123090442409.png)
#### 解析
- 实现**BeanDefinitionParser** 接口的都有一个**parse**方法直接看方法.
- 通过查看我们可以知道最终目的获取xml标签中的属性,对 **CorsConfiguration**进行初始化最后Spring中注册
```JAVA
public class CorsBeanDefinitionParser implements BeanDefinitionParser {
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
Map<String, CorsConfiguration> corsConfigurations = new LinkedHashMap<>();
List<Element> mappings = DomUtils.getChildElementsByTagName(element, "mapping");
if (mappings.isEmpty()) {
// 最简配置
CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues();
corsConfigurations.put("/**", config);
}
else {
// 单个 mapping 处理
// mvc:mapping 标签
for (Element mapping : mappings) {
// 跨域配置
CorsConfiguration config = new CorsConfiguration();
// 处理每个属性值,并且赋值
if (mapping.hasAttribute("allowed-origins")) {
String[] allowedOrigins = StringUtils.tokenizeToStringArray(mapping.getAttribute("allowed-origins"), ",");
config.setAllowedOrigins(Arrays.asList(allowedOrigins));
}
if (mapping.hasAttribute("allowed-methods")) {
String[] allowedMethods = StringUtils.tokenizeToStringArray(mapping.getAttribute("allowed-methods"), ",");
config.setAllowedMethods(Arrays.asList(allowedMethods));
}
if (mapping.hasAttribute("allowed-headers")) {
String[] allowedHeaders = StringUtils.tokenizeToStringArray(mapping.getAttribute("allowed-headers"), ",");
config.setAllowedHeaders(Arrays.asList(allowedHeaders));
}
if (mapping.hasAttribute("exposed-headers")) {
String[] exposedHeaders = StringUtils.tokenizeToStringArray(mapping.getAttribute("exposed-headers"), ",");
config.setExposedHeaders(Arrays.asList(exposedHeaders));
}
if (mapping.hasAttribute("allow-credentials")) {
config.setAllowCredentials(Boolean.parseBoolean(mapping.getAttribute("allow-credentials")));
}
if (mapping.hasAttribute("max-age")) {
config.setMaxAge(Long.parseLong(mapping.getAttribute("max-age")));
}
corsConfigurations.put(mapping.getAttribute("path"), config.applyPermitDefaultValues());
}
}
// 注册到 Spring
MvcNamespaceUtils.registerCorsConfigurations(
corsConfigurations, parserContext, parserContext.extractSource(element));
return null;
}
}
```
- 属性截图
![image-20200123090851644](/images/springMVC/clazz/image-20200123090851644.png)
- 可以看出这个是我们的第一个跨域配置的信息
- 注册方法
```java
public static RuntimeBeanReference registerCorsConfigurations(
@Nullable Map<String, CorsConfiguration> corsConfigurations,
ParserContext context, @Nullable Object source) {
// 判断是否包含跨域bean(beanName:mvcCorsConfigurations)
if (!context.getRegistry().containsBeanDefinition(CORS_CONFIGURATION_BEAN_NAME)) {
RootBeanDefinition corsDef = new RootBeanDefinition(LinkedHashMap.class);
corsDef.setSource(source);
corsDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
if (corsConfigurations != null) {
corsDef.getConstructorArgumentValues().addIndexedArgumentValue(0, corsConfigurations);
}
context.getReaderContext().getRegistry().registerBeanDefinition(CORS_CONFIGURATION_BEAN_NAME, corsDef);
// 注册组件,并且通知监听器
context.registerComponent(new BeanComponentDefinition(corsDef, CORS_CONFIGURATION_BEAN_NAME));
}
else if (corsConfigurations != null) {
// 注册bean
BeanDefinition corsDef = context.getRegistry().getBeanDefinition(CORS_CONFIGURATION_BEAN_NAME);
corsDef.getConstructorArgumentValues().addIndexedArgumentValue(0, corsConfigurations);
}
return new RuntimeBeanReference(CORS_CONFIGURATION_BEAN_NAME);
}
```
- ![image-20200123091445694](/images/springMVC/clazz/image-20200123091445694.png)
## CorsConfiguration
- 跨域信息
```JAVA
/**
* 允许请求源
*/
@Nullable
private List<String> allowedOrigins;
/**
* 允许的http方法
*/
@Nullable
private List<String> allowedMethods;
/**
*
*/
@Nullable
private List<HttpMethod> resolvedMethods = DEFAULT_METHODS;
/**
* 允许的请求头
*/
@Nullable
private List<String> allowedHeaders;
/**
* 返回的响应头
*/
@Nullable
private List<String> exposedHeaders;
/**
* 是否允许携带 cookies
*/
@Nullable
private Boolean allowCredentials;
/**
* 存货有效期
*/
@Nullable
private Long maxAge;
```
## 处理请求
- 请求处理的一部分,前置后置都还有其他处理,这里只对跨域请求进行说明
```java
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
// 判断是否为跨域请求
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
// 当前请求的跨域配置
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
```
### 判断是否跨域
- `org.springframework.web.cors.CorsUtils#isCorsRequest`
```java
public static boolean isCorsRequest(HttpServletRequest request) {
// 是否携带 请求头:Origin
return (request.getHeader(HttpHeaders.ORIGIN) != null);
}
```
### 获取跨域信息
```java
// 判断是否为跨域请求
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
// 当前请求的跨域配置
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
```
### 跨域拦截器创建
```java
protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
HandlerExecutionChain chain, @Nullable CorsConfiguration config) {
if (CorsUtils.isPreFlightRequest(request)) {
HandlerInterceptor[] interceptors = chain.getInterceptors();
chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
}
else {
// 创建跨域拦截器
chain.addInterceptor(new CorsInterceptor(config));
}
return chain;
}
```
### 跨域拦截器
```java
/**
* 跨域拦截器
*/
private class CorsInterceptor extends HandlerInterceptorAdapter implements CorsConfigurationSource {
@Nullable
private final CorsConfiguration config;
public CorsInterceptor(@Nullable CorsConfiguration config) {
this.config = config;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return corsProcessor.processRequest(this.config, request, response);
}
@Override
@Nullable
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
return this.config;
}
}
```
### DefaultCorsProcessor
- 经过跨域拦截器 **`CorsInterceptor`**之后会调用
![image-20200123093733129](/images/springMVC/clazz/image-20200123093733129.png)
```JAVA
@Override
@SuppressWarnings("resource")
public boolean processRequest(@Nullable CorsConfiguration config, HttpServletRequest request,
HttpServletResponse response) throws IOException {
// 判断是否跨域请求
if (!CorsUtils.isCorsRequest(request)) {
return true;
}
ServletServerHttpResponse serverResponse = new ServletServerHttpResponse(response);
// 判断是否有 Access-Control-Allow-Origin
if (responseHasCors(serverResponse)) {
logger.trace("Skip: response already contains \"Access-Control-Allow-Origin\"");
return true;
}
ServletServerHttpRequest serverRequest = new ServletServerHttpRequest(request);
if (WebUtils.isSameOrigin(serverRequest)) {
logger.trace("Skip: request is from same origin");
return true;
}
boolean preFlightRequest = CorsUtils.isPreFlightRequest(request);
if (config == null) {
if (preFlightRequest) {
rejectRequest(serverResponse);
return false;
}
else {
return true;
}
}
return handleInternal(serverRequest, serverResponse, config, preFlightRequest);
}
```
### 模拟请求
```
GET http://localhost:9999/json
Origin: localhost
```
变量截图
![image-20200123093032179](/images/springMVC/clazz/image-20200123093032179.png)

@ -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;
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Loading…
Cancel
Save