一、Open Feign
Declarative RESTful
client; similar RestTemplate
, OpenFeign
is a wrapper and simplification of Python JDK
( HttpURLConnection
and third-party libraries HttpClient 和 OkHttp
) and also automatically integrates it Ribbon
.
OpenFeign
It will completely proxy HTTP requests. During use, we only need dependency injection Bean
, and then call the corresponding method to pass parameters.
Feign
The first goal is to reduce HTTP API
the complexity, hoping to make HTTP calls as easy to use as RPC ;
For programmers, this shields the HTTP request response process and makes the code closer to the form of "call".
1.The difference between Feign
andOpenfeign
Feign was first maintained by Netflix , but later Netflix
it was no longer maintained. Finally, Feign was maintained by the community and renamedOpenfeign
2. Feign
The underlying principle of
Based on jdk
the localization of dynamic proxy and interface, make service calls;
From Feign
the function manual of the official document, we can know that in order to use it, we need to do the following steps
- Reference
Feign
component packagestarter
- Write
client
a class [i.e. definedFeign
interfaceAPI
] - Call the service to enable
Feign Client
annotations and declare the packages that need to be scanned, that is,http
remote calls can be made in the form of interfaces.
1.Registration FeignClient
interface
1.@EnableFeignClient
Before parsing this annotation, one thing was done, which is @Import(FeignClientsRegistrar.class)
this register; click this class to view the caller and found that it is only used in one place, and coincidentally, it is FeignClientsRegistrar
this class;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
String[] value() default {
};
String[] basePackages() default {
};
Class<?>[] basePackageClasses() default {
};
Class<?>[] defaultConfiguration() default {
};
Class<?>[] clients() default {
};
}
2.FeignClientsRegistrar
ImportBeanDefinitionRegistrar
subclass, which will cause FeignClient
the registration method to be run when the container is initialized;
class FeignClientsRegistrar
implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
.....
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// 注册FeignClient客户端的默认配置信息
registerDefaultConfiguration(metadata, registry);
// 注册Feign Client客户端
registerFeignClients(metadata, registry);
}
public void registerFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
Map<String, Object> attrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName());
// 注解类型过滤器,只扫描@FeignClient注解的接口
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
// 扫描EnableFeignClient注解定义的feign client所有包路径
for (String basePackage : basePackages) {
Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
// verify annotated class is an interface
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
// 校验@FeignClient修饰的类,必须是接口interface
Assert.isTrue(annotationMetadata.isInterface(),"@FeignClient can only be specified on an interface");
Map<String, Object> attributes =
annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
String name = getClientName(attributes);
registerClientConfiguration(registry, name,attributes.get("configuration"));
// 真正注册feign client的地方
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
// 真正注册feign client的地方,解析@FeignClient注解的配置信息,并且利用builder【FeignClientFactoryBean】进行构建client的定义信息
private void registerFeignClient(BeanDefinitionRegistry registry,
AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
// bean定义构建器:FeignClientFactoryBean.class,定义好解析的信息后,后续spring容器将根据此构建器初始化bean
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
validate(attributes);
definition.addPropertyValue("url", getUrl(attributes));
definition.addPropertyValue("path", getPath(attributes));
String name = getName(attributes);
definition.addPropertyValue("name", name);
String contextId = getContextId(attributes);
definition.addPropertyValue("contextId", contextId);
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
String alias = contextId + "FeignClient";
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
boolean primary = (Boolean) attributes.get("primary"); // has a default, won't be null
beanDefinition.setPrimary(primary);
String qualifier = getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,new String[] {
alias });
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
}
It does two things: register the default definition information of the class; register Feign Client
the definition information [subsequent initialization based on the definition bean
];
2. Get the proxy object
1.FeignClientFactoryBean
@FeignClient
The actual initialization bean
factory of the modified interface; the production Feign
object
Before looking at this factory, let’s take a look at the top-level parent classFactoryBean
public interface FactoryBean {
private Class<?> type;
private String name;
private String url;
private String contextId;
private String path;
private boolean decode404;
private ApplicationContext applicationContext;
private Class<?> fallback = void.class;
private Class<?> fallbackFactory = void.class;
...
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
From the source code, we can know that the default feign
is no downgrade strategy and downgrade factory; it is estimated that an exception is thrown directly;
FeignClient
Looking at the factory again beans
, we can basically determine bean
the core method of acquisition getObject()
;
class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
@Override
public Object getObject() throws Exception {
return getTarget();
}
/**
* @param <T> the target type of the Feign client
* @return a {@link Feign} client created with the specified data and the context
* information
*/
<T> T getTarget() {
// 从 IOC 容器获取 FeignContext,看第二步【FeignContext】
FeignContext context = this.applicationContext.getBean(FeignContext.class);
// 通过 context 创建 Feign 构造器
Feign.Builder builder = feign(context);
// 没有配置url,通过ribbon在注册中心获取服务
if (!StringUtils.hasText(this.url)) {
if (!this.name.startsWith("http")) {
this.url = "http://" + this.name;
}
else {
this.url = this.name;
}
this.url += cleanPath();
// 负载调用核心流程【1】
return (T) loadBalance(builder, context,
new HardCodedTarget<>(this.type, this.name, this.url));
}
// 如果配置了url,则直接走url
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
this.url = "http://" + this.url;
}
String url = this.url + cleanPath();
Client client = getOptional(context, Client.class);
if (client != null) {
if (client instanceof LoadBalancerFeignClient) {
// not load balancing because we have a url,
// but ribbon is on the classpath, so unwrap
client = ((LoadBalancerFeignClient) client).getDelegate();
}
builder.client(client);
}
Targeter targeter = get(context, Targeter.class);
return (T) targeter.target(this, builder, context,new HardCodedTarget<>(this.type, this.name, url));
}
// 负载调用核心流程【2】:获取client对象--->调用
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,HardCodedTarget<T> target) {
// 获取客户端类型,看第三步【Client】
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
Targeter targeter = get(context, Targeter.class);
return targeter.target(this, builder, context, target);
}
throw new IllegalStateException(
"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
}
}
2.FeignContext
At startup, Feign
configuration information will be initialized and a context will be injected bean
;
FeignAutoConfiguration
There is initialization in ; in addition, there is startup configuration spring.facotries
in ;FeignAutoConfiguration
@Configuration
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({
FeignClientProperties.class,FeignHttpClientProperties.class })
public class FeignAutoConfiguration {
@Autowired(required = false)
private List<FeignClientSpecification> configurations = new ArrayList<>();
@Bean
public HasFeatures feignFeature() {
return HasFeatures.namedFeature("Feign", Feign.class);
}
@Bean
public FeignContext feignContext() {
FeignContext context = new FeignContext();
context.setConfigurations(this.configurations);
return context;
}
....
}
3.Client
Feign
Sending requests and receiving responses are all Client
completed by this class by default Client.Default
, and it also supports HttpClient、OkHttp
other clients;
Let’s take another look at FeignClientFactoryBean
the load strategy;
// 负载调用核心流程:获取client对象--->调用
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,HardCodedTarget<T> target) {
// 获取客户端类型,client如果没有配置第三方则使用默认的Client【feign包下】
Client client = getOptional(context, Client.class);
if (client != null) {
// 设置客户端类型
builder.client(client);
// Target也是如此,此处使用默认的feign包下的Targeter
Targeter targeter = get(context, Targeter.class);
// 核心流程:看下面第四步【Target】源码
return targeter.target(this, builder, context, target);
}
throw new IllegalStateException(
"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
}
4.Target
Target
There are 2 implementation classes, which Hystrix
are used by default when no plug-in is configured.DefaultTargeter
interface Targeter {
<T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target);
}
class DefaultTargeter implements Targeter {
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
// 接第三步【Target】的targeter.target(this, builder, context, target);
// 直接走向地5步【feign】
return feign.target(target);
}
}
class HystrixTargeter implements Targeter {
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
return feign.target(target);
}
feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
SetterFactory setterFactory = getOptional(factory.getName(), context,
SetterFactory.class);
if (setterFactory != null) {
builder.setterFactory(setterFactory);
}
Class<?> fallback = factory.getFallback();
if (fallback != void.class) {
return targetWithFallback(factory.getName(), context, target, builder,
fallback);
}
Class<?> fallbackFactory = factory.getFallbackFactory();
if (fallbackFactory != void.class) {
return targetWithFallbackFactory(factory.getName(), context, target, builder,
fallbackFactory);
}
return feign.target(target);
}
....
}
5.Feign
public abstract class Feign {
public static Builder builder() {
return new Builder();
}
// 接第四步的方法
public <T> T target(Target<T> target) {
return build().newInstance(target);
}
public Feign build() {
// 这一行,非常之重要
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404, closeAfterDecode, propagationPolicy);
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
// 找到了,ReflectiveFeign,看第六步【ReflectiveFeign】,获取到对象后,再调用其instance方法,对应:build().newInstance(target);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
}
6.ReflectiveFeign
At this point, we have found the core return objectReflectiveFeign
Moreover, it can be found that the object returned is actually obtained Feign
by a dynamic proxy through the method;newInstance()
public class ReflectiveFeign extends Feign {
private final ParseHandlersByName targetToHandlersByName;
private final InvocationHandlerFactory factory;
private final QueryMapEncoder queryMapEncoder;
// 接第五步的的代码: new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder)
ReflectiveFeign(ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory,
QueryMapEncoder queryMapEncoder) {
this.targetToHandlersByName = targetToHandlersByName;
this.factory = factory;
this.queryMapEncoder = queryMapEncoder;
}
// 再返回到第五步【Feign】的代码:build().newInstance(target);
@Override
public <T> T newInstance(Target<T> target) {
// 1.处理 @FeignCLient 注解(SpringMvc 注解等)封装为 MethodHandler 包装类
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
// 2.遍历接口中所有方法,过滤 Object 方法,并将默认方法以及 FeignClient 方法分类
for (Method method : target.type().getMethods()) {
if (method.getDeclaringClass() == Object.class) {
continue;
} else if (Util.isDefault(method)) {
DefaultMethodHandler handler = new DefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
} else {
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
// 3.通过工厂方法create(),返回代理对象,看第七步【FeignInvocationHandler】
InvocationHandler handler = factory.create(target, methodToHandler);
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[] {
target.type()}, handler);
// 4.接口内 default 方法 绑定动态代理类
for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
}
7.FeignInvocationHandler
In fact, it is ReflectiveFeign
a static class in the class department;
InvocationHandler handler = factory.create(target, methodToHandler);
In other words, the proxy here actually returns FeignInvocationHandler
;
static class FeignInvocationHandler implements InvocationHandler {
private final Target target;
private final Map<Method, MethodHandler> dispatch;
FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("equals".equals(method.getName())) {
try {
Object otherHandler =
args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return equals(otherHandler);
} catch (IllegalArgumentException e) {
return false;
}
} else if ("hashCode".equals(method.getName())) {
return hashCode();
} else if ("toString".equals(method.getName())) {
return toString();
}
return dispatch.get(method).invoke(args);
}
}
3. Http
Call
Then go back and look at Feign
the source code of the class;
return toFeign
buid
This section of the method is very important;
// 这个synchronousMethodHandlerFactory将会是jdk代理最终的处理器
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404, closeAfterDecode, propagationPolicy);
ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
As you can see, the processor created using the factory method passes a parameter, which is SynchronousMethodHandler
of type; coincidentally, it is also a processor of a dynamic proxy;
But in our previous source code, we read this line of source code [``InvocationHandler handler = factory.create(target, methodToHandler); 】时,给的解释是,返回的命名是
FeignInvokeHandler ,那既然处理器是它,
proxy 代理对象执行的时候,那也应该是看这个里面的
invoke` method;
static class FeignInvocationHandler implements InvocationHandler {
private final Target target;
private final Map<Method, MethodHandler> dispatch;
FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("equals".equals(method.getName())) {
try {
Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return equals(otherHandler);
} catch (IllegalArgumentException e) {
return false;
}
} else if ("hashCode".equals(method.getName())) {
return hashCode();
} else if ("toString".equals(method.getName())) {
return toString();
}
return dispatch.get(method).invoke(args);
}
}
It doesn’t look like it, and there is no code related to remote calling;
However dispatch
, this is an initialized assignment when the factory is created, and it is SynchronousMethodHandler
a type;
And it's very interesting here. The value it returns is the method SynchronousMethodHandler
of calling the object invoke
. Note that this is not a proxy, but a simple method call;
Because if it is jdk
a proxy, invoke
it must have three parameters: the proxy object, the interface method of the proxy object, and the interface method parameters of the proxy object.
public Object invoke(Object proxy, Method method, Object[] args){
}
SynchronousMethodHandler
RequestTemplate
:BuildRequest
template classOptions
:Storage configuration classes such as connection and timeout timeRetryer
:Failure retry strategy class
final class SynchronousMethodHandler implements MethodHandler {
private static final long MAX_RESPONSE_BUFFER_SIZE = 8192L;
private final MethodMetadata metadata;
// jdk动态代理的目标类
private final Target<?> target;
private final Client client;
private final Retryer retryer;
private final List<RequestInterceptor> requestInterceptors;
...
...
private final List<RequestInterceptor> requestInterceptors;
...
...
private final RequestTemplate.Factory buildTemplateFromArgs;
...
...
// 获取代理对象后,代理执行的核心方法
@Override
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = buildTemplateFromArgs.create(argv);
Retryer retryer = this.retryer.clone();
while (true) {
try {
// 执行调用逻辑
return executeAndDecode(template);
} catch (RetryableException e) {
try {
// 控制重试次数
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
if (propagationPolicy == UNWRAP && cause != null) {
throw cause;
} else {
throw th;
}
}
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
...
...
// 核心远程调用的逻辑
Object executeAndDecode(RequestTemplate template) throws Throwable {
// 1.循环执行fein的拦截器
Request request = targetRequest(template);
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
Response response;
long start = System.nanoTime();
try {
// 2.远程调用
response = client.execute(request, options);
} catch (IOException e) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
}
throw errorExecuting(request, e);
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
boolean shouldClose = true;
// 3.处理接口响应
try {
if (logLevel != Logger.Level.NONE) {
response =
logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);
}
if (Response.class == metadata.returnType()) {
if (response.body() == null) {
return response;
}
if (response.body().length() == null ||
response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
shouldClose = false;
return response;
}
// Ensure the response body is disconnected
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
return response.toBuilder().body(bodyData).build();
}
if (response.status() >= 200 && response.status() < 300) {
if (void.class == metadata.returnType()) {
return null;
} else {
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
}
} else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
} else {
throw errorDecoder.decode(metadata.configKey(), response);
}
} catch (IOException e) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);
}
throw errorReading(request, response, e);
} finally {
if (shouldClose) {
ensureClosed(response.body());
}
}
}
}
4. Interview narration
1. In terms of usage, when we write feign
an interface, we must controller
define the interface level, that is, the localization of the interface;
2. From @EnableFeignClient
the beginning, through the mechanism Feign
provided by the component , automatic injection and initialization are ensured, which ensures the analysis of the package path, and then to the defined factory class . Basically, the interface and configuration we wrote can already allow the container to manage them. Already;spring.factories
FeignClientRegistrar
FeigClient
FeignClient
FeignClientFactoryBean
Spring
3. The Feign
integrated Ribbon
plug-in can help us obtain different service information from the registration center and allow us to use some load strategies. This ensures that the interface is routed between services;
4. When we call these interfaces in the code feign
, we actually jdk
operate through the dynamic mode. By calling the interface, the dynamic proxy mechanism will be directly triggered, and the corresponding reflection processor will be executed InnovocationHandler
to obtain the proxy object;
5. For openFeign
, it encapsulates a dynamic proxy FeignInvocationHandler
. During initialization, the mapping information of [Method -> Method Processor] is defined. map
Through the proxy mechanism, when the call is triggered, invoke
the method is automatically called to get the method processor. , and make another invoke
call [this invoke
is not a proxy], and finally configure our FeignClient
above configuration, which includes the resolution of service names and other uri
resolutions. The components here Feign
use the top-level parent class Client
and Target
provide default The processing mechanism and extensible okhttp以及hystrix
mechanism are combined with ribbon
finding the relevant service information in the registration center and escaping uri
the http
interface into a local interface call for the specific service;
This completes the process! The design is very clever. In the whole process, there is no actual method call, but through the dynamic proxy invoke
mechanism, it helps us complete the call of the entire service;
This piece of code is quite convoluted, and you need to be jdk动态代理
very familiar with it. If you are not familiar with it, you will be circumvented;
Proxy object :HardCodedTarget
public static class HardCodedTarget<T> implements Target<T> {
private final Class<T> type;
private final String name;
private final String url;
public HardCodedTarget(Class<T> type, String url) {
this(type, url, url);
}
public HardCodedTarget(Class<T> type, String name, String url) {
this.type = checkNotNull(type, "type");
this.name = checkNotNull(emptyToNull(name), "name");
this.url = checkNotNull(emptyToNull(url), "url");
}
}
Processor :FeignInvocationHandler
acting
Proxy.newProxyInstance
Method parameter description: class loader of proxy object, interface of proxy object, processor of proxy (inherited jdk
, InvocationHandler
and overridden invoke
method)
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[] {target.type()}, handler);
5.Extended source code
Note that FeignClientRegistrar
the top-level parent classImportBeanDefinitionRegistrar
ofinvokeBeanFactoryPostProcessors(beanFactory);
This step is Srping
open to developers, allowing us to control the registered definition information, which means that the interface we define operates under this rule and can be Spring
managed;
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备,记录容器的启动时间startupDate, 标记容器为激活,初始化上下文环境如文件路径信息,验证必填属性是否填写
prepareRefresh();
// 创建容器DefaultListableBeanFactory, 接着扫描classpath路径下的所有的Bean信息,并生成对应的BeanDefinition
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 设置beanFactory类加载器,添加多个beanPostProcesser
prepareBeanFactory(beanFactory);
try {
// 这个方法是个空实现,但是web模块中使用这个注入web的一些特有的ServletContextAwareProcessor实现类
postProcessBeanFactory(beanFactory);
// 调用BeanFactoryPostProcessor各个实现类的方法:允许用户自定义改变bean的定义信息
invokeBeanFactoryPostProcessors(beanFactory);
// 注册BeanPostProcessor的实现类。 在bean创建过程中调用
registerBeanPostProcessors(beanFactory);
// 初始化国际化的资源信息放入容器中
initMessageSource();
// 初始化spring的消息监听器
initApplicationEventMulticaster();
// 在这个子类中,这个方法被用来 初始化WebServer, 并启动服务。 tomcat就是在这里启动
onRefresh();
// 注册事件监听器
registerListeners();
// 实例化所有单利的bean信息,不包括lazy-init的
finishBeanFactoryInitialization(beanFactory);
// 这里会清空一些只在启动中有用的缓存信息,广播启动成功的事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}