一、Open Feign
声明式 RESTful
客户端;类似于 RestTemplate
,OpenFeign
是对 JDK
的 HttpURLConnection
(以及第三方库 HttpClient 和 OkHttp
)的包装和简化,并且还自动整合了 Ribbon
。
OpenFeign
会完全代理 HTTP 的请求,在使用过程中我们只需要依赖注入 Bean
,然后调用对应的方法传递参数即可。
Feign
的第一个目标是减少HTTP API
的复杂性,希望能将HTTP调用做到像RPC一样易用;
这对程序员而言屏蔽了 HTTP 的请求响应过程,让代码更趋近于『调用』的形式。
1.Feign
和 Openfeign
的区别
Feign 最早是由 Netflix 公司进行维护的,后来 Netflix
不再对其进行维护,最终 Feign 由社区进行维护,更名为 Openfeign
2.Feign
的底层原理
基于jdk
的动态代理和接口的本地化,做的服务调用;
从官方文档的Feign
功能手册,我们可以知道,要想使用需要做以下的步骤
- 引用
Feign
组件包starter
- 编写
client
类【即定义Feign
的API
接口】 - 调用服务开启
Feign Client
注解,并声明需要扫描的包,即可以接口形式做http
远程调用
1.注册 FeignClient
接口
1.@EnableFeignClient
在解析这个注解之前,做了一件事,就是@Import(FeignClientsRegistrar.class)
这个注册器;单击这个类查看调用方发现,只有一个地方用了它,并且很巧,就是FeignClientsRegistrar
这个类;
@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
的子类,这会使容器初始化时,运行FeignClient
的注册方法;
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);
}
}
它做了两件事情:注册类的默认定义信息;注册Feign Client
的定义信息【后续依据定义初始化bean
】;
2.获取代理对象
1.FeignClientFactoryBean
@FeignClient
修饰的接口的实际初始化的bean
工厂;生产Feign
对象
在看这个工厂之前,先看下顶级父类FactoryBean
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;
}
}
通过源码可以知道,默认的feign
是没有降级策略和降级工厂的;估计是直接抛出异常了;
再看看FeignClient
的工厂beans
,基本上可以确定,获取bean
的核心方法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
启动时,会初始化Feign
配置信息,并注入一个上下文bean
;
在FeignAutoConfiguration
有初始化;另外,spring.facotries
中又有对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
发送请求以及接收响应等都是由 Client
完成,该类默认 Client.Default
,另外支持 HttpClient、OkHttp
等客户端;
再看一下FeignClientFactoryBean
的负载策略;
// 负载调用核心流程:获取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
有2个实现类,在没有配置Hystrix
插件的时候,是默认使用的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
至此,我们找到了核心的返回对象ReflectiveFeign
并且,可以发现,实际上返回的Feign
对象,其实是一个动态代理通过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
其实是ReflectiveFeign
类部的一个静态类;
InvocationHandler handler = factory.create(target, methodToHandler);
也就是说,此处的代理,返回的实际是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
调用
再返回看Feign
类的源码;
回到Feign
buid
方法中这一段很重要;
// 这个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);
可以看到,使用工厂方法创建的处理器传了一个参数,它是SynchronousMethodHandler
类型的;很巧,它也是一个动态代理的一个处理器;
但是我们之前的源码,读到这一行源码【``InvocationHandler handler = factory.create(target, methodToHandler);】时,给的解释是,返回的命名是
FeignInvokeHandler,那既然处理器是它,
proxy代理对象执行的时候,那也应该是看这个里面的
invoke`方法;
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);
}
}
看着不太像,里面也没有远程调用的相关代码;
但是dispatch
,这个是创建工厂时,做了初始化的赋值,它是SynchronousMethodHandler
类型;
而且这里面它很有意思,它返回的值,是调用SynchronousMethodHandler
对象的invoke
方法,注意,这块可不是代理,而是简单的方法调用;
因为如果是jdk
的代理,invoke
必须由三个参数:代理对象、代理对象的接口方法,代理对象的接口方法参数
public Object invoke(Object proxy, Method method, Object[] args){
}
SynchronousMethodHandler
RequestTemplate
:构建Request
模版类Options
:存放连接、超时时间等配置类Retryer
:失败重试策略类
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.面试口述
1.从使用上来说,我们编写feign
接口,必定需要去做controller
的接口层面定义,即接口的本地化;
2.从@EnableFeignClient
开始,通过Feign
组件提供的spring.factories
机制,自动注入和初始化FeignClientRegistrar
,这就保证了对FeigClient
包路径的解析,再到定义FeignClient
的工厂类FeignClientFactoryBean
,基本上我们编写的接口和配置,已经可以让Spring
容器对他们进行管理了;
3.通过Feign
集成的Ribbon
插件,可以帮助我们从注册中心获取到不同的服务信息,并且允许我们使用一些负载策略。这就保证了接口在服务之间的路由问题;
4.那么我们在代码里面调用这些feign
接口的时候,实际上是通过jdk
的动态模式去操作的,通过调用接口,直接会触发动态代理机制,执行对应的反射处理器InnovocationHandler
,来获取代理对象;
5.对于openFeign
来说,它这里封装了动态代理FeignInvocationHandler
,初始化时,定义好了【方法->方法处理器】的map
映射信息,通过代理机制,在触发调用时,自动调用invoke
方法,来拿到方法处理器,并再做一次invoke
调用【此处invoke
不是代理】,最终将我们在FeignClient
上面的配置,这就包括服务名的解析、还有uri
的解析,这里面Feign
组件使用的都是顶级的父类Client
和Target
,并且提供默认的处理机制,和可扩展的okhttp以及hystrix
机制,再配合ribbon
在注册中心找到相关服务的信息,配合uri
转义成http
接口到具体服务的本地接口调用;
这样整个流程就结束了!里面设计的非常巧妙,在整个过程中,并没有实际的方法调用,但是通过动态代理的invoke
机制,帮助我们完成了整个服务的调用;
这块代码比较绕,而且需要对jdk动态代理
非常熟悉才行,如果不熟悉的话,会被绕进去;
代理对象: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");
}
}
处理器:FeignInvocationHandler
代理
Proxy.newProxyInstance
方法参数说明:代理对象的类加载器、代理对象的接口、代理的处理器(继承jdk
的InvocationHandler
,并重写invoke
方法)
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[] {target.type()}, handler);
5.扩展源码
注意,FeignClientRegistrar
的顶级父类ImportBeanDefinitionRegistrar
,这将会在容器的启动中的invokeBeanFactoryPostProcessors(beanFactory);
这一步里面,是Srping
开放给开发者,允许我们对注册的定义信息做控制,这意味着我们定义的接口在这个规则下操作,可以被Spring
管理;
@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();
}
}
}