SpringMVC

总结:

  1. 首先请求进入DispatcherServlet 由DispatcherServlet 从HandlerMappings中提取对应的Handler。
  2. 2.此时只是获取到了对应的Handle,然后得去寻找对应的适配器,即:HandlerAdapter。
  3. 拿到对应HandlerAdapter时,这时候开始调用对应的Handler处理业务逻辑了。 (这时候实际上已经执行完了我们的Controller) 执行完成之后返回一个ModeAndView
  4. 这时候交给我们的ViewResolver通过视图名称查找出对应的视图然后返回。
  5. 最后 渲染视图 返回渲染后的视图 –>响应请求。

初始化过程

version 5.3.8

1
2
3
4
5
6
7
// org.springframework.web.servlet.HttpServletBean#init
@Override
public final void init() throws ServletException {
// 子类实现,初始化web环境
// Let subclasses do whatever initialization they like.
initServletBean();
}
1
2
3
4
5
6
7
8
// org.springframework.web.servlet.FrameworkServlet#initServletBean
@Override
protected final void initServletBean() throws ServletException {
// 初始化spring上下文
this.webApplicationContext = initWebApplicationContext();
// 子类实现
initFrameworkServlet();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;

if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}

//配置和刷新spring容器(重要)
//这个无非就是初始化spring ioc的环境,创建bean和实例化bean等操作
//这个方法最终也是调用refresh()方法,已在spring源码解析中解析过了
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}

if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
synchronized (this.onRefreshMonitor) {
// 初始化DispatcherServlet的配置initStrategies()
onRefresh(wac);
}
}

if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}

return wac;
}
1
2
3
4
5
// org.springframework.web.servlet.DispatcherServlet#onRefresh	
protected void onRefresh(ApplicationContext context) {
// //初始化springmvc的配置
initStrategies(context);
}

总体流程:

  • 执行DispatcherServlet的init()方法,

  • 会执行父类的HttpServletBean的init()方法

  • 然后调用了FrameworkServlet的initServletBean()方法

没看懂,执行initWebApplicationContext()方法,就是对spring ioc环境的初始化。那么这里就衍生出了一个面试题:spring容器和spring mvc的容器的区别?通过源码的分析,spring和spring mvc底层,都是调用了同一个refresh()方法,所以spring容器和spring mvc容器是没有区别的,都是指的是同一个容器。

(3)执行到onRefresh()方法,就是开始初始化DispatcherServlet了,也就是开始初始化spring mvc。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// org.springframework.web.servlet.DispatcherServlet#initStrategies	
protected void initStrategies(ApplicationContext context) {
//上传文件
initMultipartResolver(context);
//国际化
initLocaleResolver(context);
//前段的主题样式
initThemeResolver(context);
//初始化HandlerMappings(请求映射器)重点
initHandlerMappings(context);
// 初始化HandlerAdapters(处理适配器)
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
//视图转换器
initViewResolvers(context);
//重定向数据管理器
initFlashMapManager(context);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// org.springframework.web.servlet.DispatcherServlet#initHandlerMappings
private void initHandlerMappings(ApplicationContext context) {

// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
// 通过配置文件中的配置信息,得到handlerMappings
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// org.springframework.web.servlet.DispatcherServlet#getDefaultStrategies

private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {

if (defaultStrategies == null) {
try {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
/**
* 从属性文件加载默认策略实现
* 说白了这里的意思就是从DEFAULT_STRATEGIES_PATH这个文件当中拿出所有的配置
* 可以去数一下一共有8个: DispatcherServlet.properties == DEFAULT_STRATEGIES_PATH
*/
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}

String key = strategyInterface.getName();
// defaultStrategies 是DispatcherServlet.properties 配置文件,在static静态代码块初始化
// 版本变了,不是从静态方法中获取到的
String value = defaultStrategies.getProperty(key);
if (value != null) {
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(classNames.length);
for (String className : classNames) {
try {
// 获取class字节码文件
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
// 底层是通过调用spring的getBean的方式创建该对象(可以进行bean的属性装配)
// 请求映射就是在这个方法实现装配的
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
catch (ClassNotFoundException ex) {
throw new BeanInitializationException(
"Could not find DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]", ex);
}
catch (LinkageError err) {
throw new BeanInitializationException(
"Unresolvable class definition for DispatcherServlet's default strategy class [" +
className + "] for interface [" + key + "]", err);
}
}
return strategies;
}
else {
return Collections.emptyList();
}
}

DispatcherServlet.properties

从DispatcherServlet.properties配置文件,可以看出handlerMapping默认是有两个:

1.BeanNameUrlHandlerMapping (主要处理object)

2.RequestMappingHandlerMapping(主要处理method)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver


// HandlerMapping
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
org.springframework.web.servlet.function.support.RouterFunctionMapping

// HandlerAdapter
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
org.springframework.web.servlet.function.support.HandlerFunctionAdapter


org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

(1) initHandlerMappings方法,就是初始化我们的handlerMapping(请求映射器)。

(2) handlerMapping的主要作用是,找到请求路径对应的controller的方法。

例如:请求的路径 “/index”,然后这个handlerMapping,在初始化的时候,已经将所有controller的请求路径映射保存在一个map集合,当请求过来的时候,就将”/index”作为一个key,从map集合中找到对应的controller的index方法。

(3) 这里初始化handlerMappings ,默认是有两个handlerMappings ,是直接在defaultStrategies配置文件中获取。

(4) 那么defaultStrategies的值是什么时候初始化的呢?

通过查看源码,defaultStrategies这个值,是DispatcherServlet类的静态代码块初始化的。 全世界都知道,当一个类被初始化的时候,会执行该类的static静态代码块的。

请求阶段分析

用户的一个请求过来,会由servlet接收到,然后一步一步调用到DispatcherServlet的doService方法。

1
2
3
4
5
6
// org.springframework.web.servlet.DispatcherServlet#doService
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 核心方法(重点)
doDispatch(request, response);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// org.springframework.web.servlet.DispatcherServlet#doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;

// 异步编程
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {
// 定义变量,哈哈哈,好熟悉呀
ModelAndView mv = null;
Exception dispatchException = null;

try {
//检查请求中是否有文件上传操作
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);

// Determine handler for the current request.
// 确定当前请求的处理程序(重点),推断controller和handler的类型,
// 进到这里的getHandler方法
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}

// Determine handler adapter for the current request.
//推断适配器,不同的controller类型,交给不同的适配器去处理
//如果是一个bean,mappedHandler.getHandler()返回的是一个对象
//如果是一个method,mappedHandler.getHandler()返回的是一个方法
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//到这里,spring才确定我要怎么反射调用

// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}

// 前置拦截器处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

//通过适配器,处理请求(可以理解为,反射调用方法)(重点)
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
return;
}

applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
}

通过对DispatcherServlet的分析,得到请求的核心处理方法是doDispatch(),

主要是分了几步:

(1) 检查请求中是否有文件上传操作

(2) 确定当前请求的处理的handler(重点)

(3) 推断适配器,不同的controller类型,交给不同的适配器去处理

(4) 执行前置拦截器处理interceptor

(5) 通过找到的HandlerAdapter ,反射执行相关的业务代码controller的方法。

(6) 返回结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// org.springframework.web.servlet.DispatcherServlet#getHandler
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
//循环所有的HandlerMappings
//this.handlerMappings这个是什么时候初始化的?(重点)
//在handlerMappings初始化的时候
for (HandlerMapping mapping : this.handlerMappings) {
//把请求传过去看能不能得到一个handler
//注意:怎么得到handler和handlerMapping自己实现的逻辑有关系
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//获取handler(重点)
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);
}

// Ensure presence of cached lookupPath for interceptors and others
if (!ServletRequestPathUtils.hasCachedPath(request)) {
initLookupPath(request);
}

HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {
logger.debug("Mapped to " + executionChain.getHandler());
}

if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = getCorsConfiguration(handler, request);
if (getCorsConfigurationSource() != null) {
CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
config = (globalConfig != null ? globalConfig.combine(config) : config);
}
if (config != null) {
config.validateAllowCredentials();
}
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}

return executionChain;
}

(1) getHandler()方法,主要是遍历在DispatcherServlet初始化是,初始化的handlerMappings。

(2) 这个方法的主要思想是,通过request的路径,去匹配对应的controller去处理。

(3) SpringMVC自己自带了2个HandlerMapping 来供我们选择 至于 为什么要有2个呢?

两种注册Controller的方式

我们用2种方式来注册Controller 分别是:

(1) 作为Bean的形式:实现Controller接口,重写handleRequest方法,请求路径为”/test”

1
2
3
4
5
6
7
8
9
@Component("/test")
public class TesrController implements org.springframework.web.servlet.mvc.Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out.println("1");
return null;
}
}

(2) 以Annotation形式:

1
2
3
4
5
6
7
8
@Controller
public class AnnotationController {
@RequestMapping("/test2")
public Object test(){
System.out.println("test");
return null;
}
}

经过测试:

(1)可以得到以Bean方式的controller,是通过BeanNameUrlHandlerMapping去匹配

(2)以注解方法的controller,是通过RequestMappingHandlerMapping去匹配

BeanNameUrlHandlerMapping

BeanNameUrlHandlerMapping处理bean方式的源码分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#getHandlerInternal
@Override
@Nullable
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
// 获取请求的路径
String lookupPath = initLookupPath(request);
// 到对应的handler(重点)调用 lookupHandler()
Object handler;
if (usesPathPatterns()) {
RequestPath path = ServletRequestPathUtils.getParsedRequestPath(request);
handler = lookupHandler(path, lookupPath, request);
}
else {
handler = lookupHandler(lookupPath, request);
}
if (handler == null) {
// We need to care for the default handler directly, since we need to
// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
Object rawHandler = null;
if (StringUtils.matchesCharacter(lookupPath, '/')) {
rawHandler = getRootHandler();
}
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean name or resolved handler?
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
return handler;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#lookupHandler(java.lang.String, javax.servlet.http.HttpServletRequest)
@Nullable
protected Object lookupHandler(String lookupPath, HttpServletRequest request) throws Exception {
// 查看这里的方法
Object handler = getDirectMatch(lookupPath, request);
if (handler != null) {
return handler;
}

// Pattern match?
List<String> matchingPatterns = new ArrayList<>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, lookupPath)) {
matchingPatterns.add(registeredPattern);
}
else if (useTrailingSlashMatch()) {
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", lookupPath)) {
matchingPatterns.add(registeredPattern + "/");
}
}
}

String bestMatch = null;
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(lookupPath);
if (!matchingPatterns.isEmpty()) {
matchingPatterns.sort(patternComparator);
if (logger.isTraceEnabled() && matchingPatterns.size() > 1) {
logger.trace("Matching patterns " + matchingPatterns);
}
bestMatch = matchingPatterns.get(0);
}
if (bestMatch != null) {
handler = this.handlerMap.get(bestMatch);
if (handler == null) {
if (bestMatch.endsWith("/")) {
handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
}
if (handler == null) {
throw new IllegalStateException(
"Could not find handler for best pattern match [" + bestMatch + "]");
}
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, lookupPath);

// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
// for all of them
Map<String, String> uriTemplateVariables = new LinkedHashMap<>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, lookupPath);
Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
if (logger.isTraceEnabled() && uriTemplateVariables.size() > 0) {
logger.trace("URI variables " + uriTemplateVariables);
}
return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
}

// No handler found...
return null;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#getDirectMatch
@Nullable
private Object getDirectMatch(String urlPath, HttpServletRequest request) throws Exception {
// 通过请求的路径,在handlerMap中去匹配。
// handlerMap这个值,什么时候填充值?在init初始化的时候,就已经存放在这个handlerMap种
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
return null;
}

(1) 以Bean方式的controller,匹配请求的路径,是通过一个handlerMap去匹配,比较简单。

(2) 这里的问题是,这个handlerMap的值,是什么时候放进去的?

通过源码分析,BeanNameUrlHandlerMapping是实现了ApplicationContextAware接口。 如果你精通spring的源码,就知道spring的实例bean的时候,会回调这些类的setApplicationContext()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// org.springframework.context.support.ApplicationObjectSupport#setApplicationContext
@Override
public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
if (context == null && !isContextRequired()) {
// Reset internal context state.
this.applicationContext = null;
this.messageSourceAccessor = null;
}
else if (this.applicationContext == null) {
// Initialize with passed-in context.
if (!requiredContextClass().isInstance(context)) {
throw new ApplicationContextException(
"Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
}
this.applicationContext = context;
this.messageSourceAccessor = new MessageSourceAccessor(context);
// 初始化ApplicationContext,就会执行到子类的方法(重点)
initApplicationContext(context);
}
else {
// Ignore reinitialization if same context passed in.
if (this.applicationContext != context) {
throw new ApplicationContextException(
"Cannot reinitialize with different application context: current one is [" +
this.applicationContext + "], passed-in one is [" + context + "]");
}
}
}
1
2
3
4
5
6
7
8
9
// 没看懂怎么走到这里来呢
// org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping#initApplicationContext
@Override
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
// 检测出handler
detectHandlers();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping#detectHandlers
protected void detectHandlers() throws BeansException {
// 获取spring ioc所有的beanName,然后判断beanName,那些是以 "/" 开头
ApplicationContext applicationContext = obtainApplicationContext();
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
applicationContext.getBeanNamesForType(Object.class));

// Take any bean name that we can determine URLs for.
for (String beanName : beanNames) {
// 然后判断beanName,那些是以 "/" 开头
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// 注册handler(重点)
// URL paths found: Let's consider it a handler.
registerHandler(urls, beanName);
}
}
}
1
2
3
4
5
6
7
// org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#registerHandler(java.lang.String[], java.lang.String)	
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
Assert.notNull(urlPaths, "URL path array must not be null");
for (String urlPath : urlPaths) {
registerHandler(urlPath, beanName);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#registerHandler(java.lang.String, java.lang.Object)
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
Assert.notNull(urlPath, "URL path must not be null");
Assert.notNull(handler, "Handler object must not be null");
Object resolvedHandler = handler;

// Eagerly resolve handler if referencing singleton via name.
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
ApplicationContext applicationContext = obtainApplicationContext();
if (applicationContext.isSingleton(handlerName)) {
resolvedHandler = applicationContext.getBean(handlerName);
}
}

Object mappedHandler = this.handlerMap.get(urlPath);
if (mappedHandler != null) {
if (mappedHandler != resolvedHandler) {
throw new IllegalStateException(
"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
}
}
else {
if (urlPath.equals("/")) {
if (logger.isTraceEnabled()) {
logger.trace("Root mapping to " + getHandlerDescription(handler));
}
setRootHandler(resolvedHandler);
}
else if (urlPath.equals("/*")) {
if (logger.isTraceEnabled()) {
logger.trace("Default mapping to " + getHandlerDescription(handler));
}
setDefaultHandler(resolvedHandler);
}
else {
// 最终put到map集合中(省略其他无关代码)
this.handlerMap.put(urlPath, resolvedHandler);
if (getPatternParser() != null) {
this.pathPatternHandlerMap.put(getPatternParser().parse(urlPath), resolvedHandler);
}
if (logger.isTraceEnabled()) {
logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
}

BeanNameUrlHandlerMapping处理bean方式的源码分析,其实是很简单:

(1) 在类初始化的时候,就已经将所有实现了Controller接口的controller类,拿到他们的@Componet(‘/test’)

(2) 然后将’/test’这个作为key,controller类作为value,放入到一个map集合。

(3) 当一个请求过来的时候,拿到这个请求的uri,在map里面找,找到了即表示匹配上

RequestMappingHandlerMapping

处理注解方式的源码分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal
// 对于RequestMappingHandlerMapping,indexController.index(),方法的请求路径映射
@Override
@Nullable
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 获取请求路径
String lookupPath = initLookupPath(request);
this.mappingRegistry.acquireReadLock();
try {
// 通过请求路径,获取handler
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 从mappingRegistry的urlLookup,匹配请求路径
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
for (Match match : matches) {
if (match.hasCorsConfig()) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
}
}
else {
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.getHandlerMethod().getMethod();
Method m2 = secondBestMatch.getHandlerMethod().getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
handleMatch(bestMatch.mapping, lookupPath, request);
// 返回handler
return bestMatch.getHandlerMethod();
}
else {
return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
}
}
1
2
3
4
5
// 3.AbstractHandlerMethodMapping.MappingRegistry#getMappingsByDirectPath
@Nullable
public List<T> getMappingsByDirectPath(String urlPath) {
return this.pathLookup.get(urlPath);
}

RequestMappingHandlerMapping处理注解方式的源码分析,比较复杂,用一个MappingRegistry维护所有的请求路径映射。

MappingRegistry的初始化,也是在该bean实例化的时候,就已经做好的了。

原理也是和上一个差不多,都是从一个map集合里面匹配。所以这里就不再做解析了

总结:getHandler()

找适配器

1
2
3
4
5
6
7
8
9
10
11
12
// org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

其实能看见他是从一个handlerAdapters属性里面遍历了我们的适配器 这个handlerAdapters哪来的呢?

跟我们的HandlerMappings一样 在他的配置文件里面有写,就是我们刚刚所说的 。

至于什么是适配器,我们结合Handler来讲, 就如我们在最开始的总结时所说的, 一开始只是找到了Handler 现在要执行了,但是有个问题,Handler不止一个, 自然而然对应的执行方式就不同了, 这时候适配器的概念就出来了:对应不同的Handler的执行方案。当找到合适的适配器的时候, 基本上就已经收尾了,因为后面在做了一些判断之后(判断请求类型之类的),就开始执行了你的Handler了,上代码:

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

这个mv就是我们的ModlAndView 其实执行完这一行 我们的Controller的逻辑已经执行完了, 剩下的就是寻找视图 渲染图的事情了。

总结: 其实我们的SpringMVC关键的概念就在于Handler(处理器) 和Adapter(适配器) 通过一个关键的HandlerMappings 找到合适处理你的Controller的Handler 然后再通过HandlerAdapters找到一个合适的HandlerAdapter 来执行Handler即Controller里面的逻辑。 最后再返回ModlAndView…

参考:https://juejin.cn/post/6991290858880368676

Spring

事务的传播

参考:https://segmentfault.com/a/1190000013341344

传播等级 描述 理解
REQUIRED 默认的事务传播级别
表示如果当前存在事务,则加入该事务;
如果当前没有事务,则创建一个新的事务。
A有事务,B就跟着用
A没有事务,B就开启自己的事务,只B方法用
SUPPORTS 如果当前存在事务,则加入该事务;
如果当前没有事务,则以非事务的方式继续运行。
MANDATORY 如果当前存在事务,则加入该事务;
如果当前没有事务,则抛出异常。
REQUIRES_NEW 表示创建一个新的事务
如果当前存在事务,则把当前事务挂起。
也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
NOT_SUPPORTED 以非事务方式运行,
如果当前存在事务,则把当前事务挂起。
NEVER 以非事务方式运行,
如果当前存在事务,则抛出异常。
NESTED 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;
如果当前没有事务,则该取值等价于REQUIRED。

默认数据是anthony和0

REQUIRED

A方法事务,A方法报错,有一个报错都会回滚,结果是:anthony和0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@PostMapping("/test1")
@Transactional
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();

transactionalController.methodB();
int i = 1 / 0;
}

@Transactional(propagation= Propagation.REQUIRED)
public void methodB(){
Test byId = testService.getById(1);
byId.setParentId(1);
byId.updateById();
}

A方法没有事务,A方法有报错,结果是:anthony2和1

B方法自己开启事务,就不管A事务了,所以A方法,就算报错了,也成功写入数据库,B事务没有报错,也成功写入数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@PostMapping("/test1")
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();

transactionalController.methodB();
int i = 1 / 0;
}

@Transactional(propagation= Propagation.REQUIRED)
public void methodB(){
Test byId = testService.getById(1);
byId.setParentId(1);
byId.updateById();
}

A方法没有事务,A方法和B方法都报错,,结果是:anthony2和0

A方法没有事务,所以A方法插入数据库成功,就算报错,也没有回滚

B方法自己开始事务,B方法报错,所以回滚

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@PostMapping("/test1")
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();

transactionalController.methodB();
int i = 1 / 0;
}

@Transactional(propagation= Propagation.REQUIRED)
public void methodB(){
Test byId = testService.getById(1);
byId.setParentId(1);
byId.updateById();
int i = 1 / 0;
}

SUPPORTS

A方法有事务,A方法报错,都回滚,,结果是:anthony和0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@PostMapping("/test1")
@Transactional
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();

transactionalController.methodB();
int i = 1 / 0;
}

@Transactional(propagation= Propagation.SUPPORTS)
public void methodB(){
Test byId = testService.getById(1);
byId.setParentId(1);
byId.updateById();
}

A没有事务,,A方法报错,都没有回滚,结果是:anthony2和1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@PostMapping("/test1")
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();

transactionalController.methodB();
int i = 1 / 0;
}

@Transactional(propagation= Propagation.SUPPORTS)
public void methodB(){
Test byId = testService.getById(1);
byId.setParentId(1);
byId.updateById();
}

A没有事务,,A,B方法都报错,都没有回滚,结果是:anthony2和1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@PostMapping("/test1")
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();

transactionalController.methodB();
int i = 1 / 0;
}

@Transactional(propagation= Propagation.SUPPORTS)
public void methodB(){
Test byId = testService.getById(1);
byId.setParentId(1);
byId.updateById();
int i = 1 / 0;
}

MANDATORY

A有事务,A报错,都回滚,结果是:anthony和0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@PostMapping("/test1")
@Transactional
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();

transactionalController.methodB();
int i = 1 / 0;
}

@Transactional(propagation= Propagation.MANDATORY)
public void methodB(){
Test byId = testService.getById(1);
byId.setParentId(1);
byId.updateById();
}

A没有事务,运行报错了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@PostMapping("/test1")
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();

transactionalController.methodB();
int i = 1 / 0;
}

@Transactional(propagation= Propagation.MANDATORY)
public void methodB(){
Test byId = testService.getById(1);
byId.setParentId(1);
byId.updateById();
}

REQUIRES_NEW

测试的时候,不要操作同一条数据,容易超时…..

A开始事务,B也开始事务,B报错了,B回滚,A插入成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@PostMapping("/test1")
@Transactional
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();

transactionalController.methodB();
int i = 1 / 0;
}

@Transactional(propagation= Propagation.REQUIRES_NEW)
public void methodB(){
Test byId = testService.getById(2);
byId.setParentId(1);
byId.updateById();
}

这样没有复现出问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@PostMapping("/test1")
@Transactional
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();
transactionalController.methodB();
}

@Transactional(propagation= Propagation.REQUIRES_NEW)
public void methodB(){
Test byId = testService.getById(2);
byId.setParentId(1);
byId.updateById();
int i = 1 / 0;
}
  • A没有事务,B有事务
  • A报错,没有回滚,
    B插入数据成功
  • 外围方法异常,不影响内部调用的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@PostMapping("/test1")
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();

transactionalController.methodB();
int i = 1 / 0;
}

@Transactional(propagation= Propagation.REQUIRES_NEW)
public void methodB(){
Test byId = testService.getById(2);
byId.setParentId(1);
byId.updateById();
}
  • A没有事务,B有事务
  • A插入数据成功,B回滚
  • 内部调用的方法,不影响外围的方法成功插入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@PostMapping("/test1")
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();
transactionalController.methodB();
}

@Transactional(propagation= Propagation.REQUIRES_NEW)
public void methodB(){
Test byId = testService.getById(2);
byId.setParentId(1);
byId.updateById();
int i = 1 / 0;
}

NOT_SUPPORTED

A有事务,B也有事务,A回滚了,B报错了,没有回滚

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@PostMapping("/test1")
@Transactional
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();

transactionalController.methodB();

}

@Transactional(propagation= Propagation.NOT_SUPPORTED)
public void methodB(){
Test byId = testService.getById(2);
byId.setParentId(1);
byId.updateById();
int i = 1 / 0;

}

A有事务,B也有事务,A回滚了,B没有回滚

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@PostMapping("/test1")
@Transactional
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();

transactionalController.methodB();
int i = 1 / 0;

}

@Transactional(propagation= Propagation.NOT_SUPPORTED)
public void methodB(){
Test byId = testService.getById(2);
byId.setParentId(1);
byId.updateById();
int i = 1 / 0;

}

NEVER

直接报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@PostMapping("/test1")
@Transactional
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();
transactionalController.methodB();
}

@Transactional(propagation= Propagation.NEVER)
public void methodB(){
Test byId = testService.getById(2);
byId.setParentId(1);
byId.updateById();
}

NESTED

全部提交成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@PostMapping("/test1")
@Transactional
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();
transactionalController.methodB();
}

@Transactional(propagation= Propagation.NESTED)
public void methodB(){
Test byId = testService.getById(2);
byId.setParentId(1);
byId.updateById();
}

全部失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@PostMapping("/test1")
@Transactional
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();
transactionalController.methodB();
}

@Transactional(propagation= Propagation.NESTED)
public void methodB(){
Test byId = testService.getById(2);
byId.setParentId(1);
byId.updateById();
int i = 1 / 0;
}

A没有事务,B有事务

A执行成功,B回滚成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@PostMapping("/test1")
public void methodA(){
Test byId = testService.getById(1);
byId.setUsername("anthony2");
byId.updateById();
transactionalController.methodB();
}

@Transactional(propagation= Propagation.NESTED)
public void methodB(){
Test byId = testService.getById(2);
byId.setParentId(1);
byId.updateById();
int i = 1 / 0;
}

拦截器和过滤器

1、过滤器和拦截器触发时机不一样,先拦截器,后过滤器

2、拦截器可以获取IOC容器中的各个bean,而过滤器就不行,因为拦截器是spring提供并管理的,spring的功能可以被拦截器使用,在拦截器里注入一个service,可以调用业务逻辑。而过滤器是JavaEE标准,只需依赖servlet api ,不需要依赖spring。

3、过滤器的实现基于回调函数。而拦截器(代理模式)的实现基于反射

4、过滤器是依赖于Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用。

5、Filter的执行由Servlet容器回调完成,而拦截器通常通过动态代理(反射)的方式来执行。

6、Filter的生命周由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。

7、过滤器只能在请求的前后使用,而拦截器可以详细到每个方法

Spring IOC

Spring提供了两种容器:BeanFactory和ApplicationContext

  • BeanFactory:基本的IoC容器,默认采用延迟初始化策略(lazy-load),即只有当客户端对象需要访问容器中某个bean对象的时候,才会对该bean对象进行初始化以及依赖注入操作。所以BeanFactory容器的特点是启动初期速度快,所需资源有限,适合于资源有限功能要求不严格的场景。
  • ApplicationContext: ApplicationContext在BeanFactory基础上构建,支持其他的高级特性,如国际化,事件发布等。相对于BeanFactory容器来说,ApplicationContext在启动的时候即完成资源的初始化,所以启动时间较长,适合于系统资源充足,需要更多功能的场景

Spring Bean

Java 中Bean的定义:

  • 类中所有的属性都必须封装,即:使用private声明;这个不太确定
  • 封装的属性如果需要被外部所操作,则必须编写对应的setter、getter方法;
  • 一个JavaBean中至少存在一个无参构造方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Staff{

private String name;
private int age;

public void setName(String name) {
this.name = name;
}

public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}

public int getAge() {
return age;
}

}

而Spring IoC容器就是管理bean的工厂。Spring中bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。这些 bean 是由用容器提供的配置元数据创建的。Spring可以采用XML配置文件的方式来管理和配置Bean信息,如下:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="user" class="com.wgs.spring.bean.User"></bean>

</beans>

<beans>是XML配置文件中根节点,下面可包含多个<bean>子节点。Spring的XML配置文件中的配置与<bean>元素是一一对应的。

属性 描述
id 注册到容器的对象都有一个唯一的id值,如id=”user”
name bean的别名,name可以使用逗号、空格或冒号等分割指定多个name,而id就不可以
scope 作用域
constructor-arg 用来注入依赖关系
properties 用来注入依赖关系
autowiring mode 用来注入依赖关系
lazy-initialization mode 是否延迟加载
initialization method bean被创建的时候,初始化的的方法
destruction method 销毁指定的方法

Spring Bean 生命周期

2.低昂registerBeanFactoryPostProcessor  完成扫描,运行之前,不会有我们自己的类,除了@componentScan这个注解的这个类,等完成之后,就会有我们自己的类

1:实例化一个ApplicationContext的对象;2:调用bean工厂后置处理器完成扫描;3:循环解析扫描出来的类信息;4:实例化一个BeanDefinition对象来存储解析出来的信息;5:把实例化好的beanDefinition对象put到beanDefinitionMap当中缓存起来,以便后面实例化bean;6:再次调用bean工厂后置处理器;7:当然spring还会干很多事情,比如国际化,比如注册BeanPostProcessor等等,如果我们只关心如何实例化一个bean的话那么这一步就是spring调用finishBeanFactoryInitialization方法来实例化单例的bean,实例化之前spring要做验证,需要遍历所有扫描出来的类,依次判断这个bean是否Lazy,是否prototype,是否abstract等等;8:如果验证完成spring在实例化一个bean之前需要推断构造方法,因为spring实例化对象是通过构造方法反射,故而需要知道用哪个构造方法;9:推断完构造方法之后spring调用构造方法反射实例化一个对象;注意我这里说的是对象、对象、对象;这个时候对象已经实例化出来了,但是并不是一个完整的bean,最简单的体现是这个时候实例化出来的对象属性是没有注入,所以不是一个完整的bean;10:spring处理合并后的beanDefinition(合并?是spring当中非常重要的一块内容,后面的文章我会分析);11:判断是否支持循环依赖,如果支持则提前把一个工厂存入singletonFactories——map;12:判断是否需要完成属性注入13:如果需要完成属性注入,则开始注入属性14:判断bean的类型回调Aware接口15:调用生命周期回调方法16:如果需要代理则完成代理17:put到单例池——bean完成——存在spring容器当中

Spring Bean 循环依赖

https://juejin.im/post/6844904166351978504#h5

AnnotationConfigApplicationContext#AnnotationConfigApplicationContext

1
2
3
4
5
6
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
// 关键方法
refresh();
}

org.springframework.context.support.AbstractApplicationContext#refresh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
// 完成所有的扫描
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所有没有延迟的单例类
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();
}
}
}

org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization

1
2
3
4
5
6
7
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// ....

// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所有单例,非lazy
beanFactory.preInstantiateSingletons();
}

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}

// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 验证,判断这个是是不是抽象的和是不是单例的和是不是延迟加载的
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 验证一切都通过的类,开始实例化普通的bean,还不是spring bean
getBean(beanName);
}
}
}

// ....
}

org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)

1
2
3
4
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

这里面大部分都是验证,比如depenon,或者import

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {

// 理解bean的名字是否非法
String beanName = transformedBeanName(name);
Object bean;

// Eagerly check singleton cache for manually registered singletons.
// 这里的方法啊
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 判断这个类是不是在创建过程中,循环依赖的时候要用
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}

// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 方法注入
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}

if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}

try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}

// Create bean instance.
// 判断类是不是单例
if (mbd.isSingleton()) {
// getSingleton(String,facotory) 这个方法里有正在创建中的标识设置
sharedInstance = getSingleton(beanName, () -> {
try {
// 完成了目标对象的创建
// 如果需要代理,还创建了代理
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}

// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 上个代码块第七行调用的
@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}

/** Cache of singleton objects: bean name to bean instance. */
/** 缓存单例对象: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 初始化的时候这里肯定是null,但是在初始化完成之后,再调用getBean就肯定不是null
// isSingletonCurrentlyInCreation 这个方法很重要,说明对象是不是正在创建
// singletonFactories 也很重要
Object singletonObject = this.singletonObjects.get(beanName);

// 判断循环依赖的时候
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {

if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;

// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
// 从beanDefinition对象中获取出来bean的类型
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}

// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}

try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 第一次调用个后置处理器
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}

try {
// 调用方法
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {

// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 实例化对象,里面第二次调调用后置处理器
// 反射调用对象的构造方法
// 这里java对象就已经有了
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}

// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 第三次调用后置处理器
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}

mbd.postProcessed = true;
}
}

// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 判断是否需要循环依赖
boolean earlySingletonExposure =
// 到这里了,也肯定是true
(mbd.isSingleton() &&
// 默认值是true
this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));

if (earlySingletonExposure) {
// 第四次调用后置处理器,判断是否需要AOP
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

// Initialize the bean instance.
Object exposedObject = bean;
try {
// 填充属性,也就是我们说的自动注入
// 里面会完成第五次和第六次后置处理器的调用
// 看这里
populateBean(beanName, mbd, instanceWrapper);
// 初始化spring
// 里面会进行第七次和第八次后置处理的调用个
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}

if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// 省略代码
}
}
}

// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}

return exposedObject;
}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);

if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}

Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}

if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}

// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}

// Candidate constructors for autowiring?
// 第二次调用后置处理器构造方法,通过反射实例化对象,这时候构造方法里有打印,就会打印出日志
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}

// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}

// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}

// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}

PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}

boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
// 这里的ibp常用的有两种类型
// 1.@Resouce 使用的是CommonAnnotationBeanPostProcessor
// 2.@Autowire 使用的是AutoWireAnnotationBeanPostProcessor
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 这里会调用属性的注入,也就是在这里,碰到循环依赖的时候,就会调用个
// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}

if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 重点,如果没有获取到,就设置个标识,表示正在创建
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#beforeSingletonCreation

1
2
3
4
5
6
7
8
9
10
/** Names of beans that are currently in creation. */
// 添加到这里来了之后就标识当前这个bean正在创建
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));

protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory

二级缓存

1
2
3
4
5
6
7
8
9
10
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}

三个缓存

1
2
3
4
5
6
7
8
// singletonObjects:第一级缓存,里面存放的都是创建好的成品Bean。
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object(256);

// earlySingletonObjects : 第二级缓存,里面存放的都是半成品的Bean
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object(16);

// singletonFactories :第三级缓存, 不同于前两个存的是 Bean对象引用,此缓存存的bean 工厂对象,也就存的是 专门创建Bean的一个工厂对象。此缓存用于解决循环依赖
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

两个缓存能解决不

A引用创建后,提前暴露到半成品缓存中

依赖B,创建B ,B填充属性时发现依赖A, 先从成品缓存查找,没有,再从半成品缓存查找 取到A的早期引用

1
B顺利走完创建过程`, 将`B的早期引用从半成品缓存移动到成品缓存

B创建完成,A获取到B的引用,继续创建。

A创建完成,将A的早期引用从半成品缓存移动到成品缓存

为啥需要三个缓存

上面两个缓存的地方,我们只是没有考虑代理的情况。

Bean在创建的最后阶段,会检查是否需要创建代理,如果创建了代理,那么最终返回的就是代理实例的引用。我们通过beanname获取到最终是代理实例的引用

也就是说:假设A最终会创建代理,提前暴露A的引用, B填充属性时填充的是A的原始对象引用。A最终放入成品库里是代理的引用。那么B中依然是A的早期引用。这种结果最终会与我们的期望的大相径庭了。

完整的流程

关键点:

  • A绑定到ObjectFactory 注册到工厂缓存singletonFactory中,
  • B在填充A时,先查成品缓存有没有,再查半成品缓存有没有,最后看工厂缓存有没有单例工厂类,有A的ObjectFactory。调用getObject ,执行扩展逻辑,可能返回的代理引用,也可能返回原始引用。
  • 成功获取到A的早期引用,将A放入到半成品缓存中,B填充A引用完毕。
  • 代理问题, 循环依赖问题都解决了

Spring Bean 二次开发

在实例化Bean之前,Spring会调用扩展的类,实现BeanFactoryPostProcessor,并且机上@component注解,如果没有实现,spring就不会调用

Spring AOP

AOP是什么

AOP的全称是Aspect Orient Programming,即面向切面编程。是对OOP(Object Orient Programming)的一种补充,战门用于处理一些具有横切性质的服务。常常用于日志输出、安全控制等。

上面说到是对OOP的一种补充,具体补充的是什么呢?考虑一种情况,如果我们需要在所有方法执行前打印一句日志,按照OOP的处理思想,我们需要在每个业务方法开始时加入一些语句,但是我们辛辛苦苦加完之后,如果又要求在这句日志打印后再打印一句,那是不是又要加一遍?这时候你一定会想到,在某个类中编写一个日志打印方法,该方法执行这些日志打印操作,然后在每个业务方法之前加入这句方法调用,这就是面向对象编程思想。但是如果要求我们在业务方法结束时再打印一些日志呢,是不是还要去每个业务方法结束时加一遍?这样始终不是办法,而且我们总是在改业务方法,在业务方法里面掺杂了太多的其他操作,侵入性太高。

这时候AOP就起到作用了,我们可以编写一个切面类(Aspect),在其中的方法中来编写横切逻辑(如打印日志),然后通过配置或者注解的方式来声明该横切逻辑起作用的位置。

实现技术

AOP(这里的AOP指的是面向切面编程思想,而不是Spring AOP)主要的的实现技术主要有Spring AOP和AspectJ。

1、AspectJ的底层技术。

AspectJ的底层技术是静态代理,即用一种AspectJ支持的特定语言编写切面,通过一个命令来编译,生成一个新的代理类,该代理类增强了业务类,这是在编译时增强,相对于下面说的运行时增强,编译时增强的性能更好。

2、Spring AOP

Spring AOP采用的是动态代理,在运行期间对业务方法进行增强,所以不会生成新类,对于动态代理技术,Spring AOP提供了对JDK动态代理的支持以及CGLib的支持。

JDK动态代理只能为接口创建动态代理实例,而不能对类创建动态代理。需要获得被目标类的接口信息(应用Java的反射技术),生成一个实现了代理接口的动态代理类(字节码),再通过反射机制获得动态代理类的构造函数,利用构造函数生成动态代理类的实例对象,在调用具体方法前调用invokeHandler方法来处理。

CGLib动态代理需要依赖asm包,把被代理对象类的class文件加载进来,修改其字节码生成子类。

但是Spring AOP基于注解配置的情况下,需要依赖于AspectJ包的标准注解,但是不需要额外的编译以及AspectJ的织入器,而基于XML配置不需要。

知识点

PointCut

你想要去切某个东西之前总得先知道要在哪里切入是吧,切点格式如下:execution(* com.nuofankj.springdemo.aop.*Service.*(..))格式使用了正常表达式来定义那个范围内的类、那些接口会被当成切点

Advice

通知,所谓的Advice其实就是定义了Aop何时被调用,确实有种通知的感觉

  • Before 在方法被调用之前调用
  • After 在方法完成之后调用
  • After-returning 在方法成功执行之后调用
  • After-throwing 在方法抛出异常之后调用
  • Around 在被通知的方法调用之前和调用之后调用

JoinPoint

JoinPoint连接点,其实很好理解,上面又有通知、又有切点,那和具体业务的连接点又是什么呢?没错,其实就是对应业务的方法对象,因为我们在横切代码中是有可能需要用到具体方法中的具体数据的,而连接点便可以做到这一点。

Aspect

就是我们关注点的模块化。这个关注点可能会横切多个对象和模块,事务管理是横切关注点的很好的例子。它是一个抽象的概念,从软件的角度来说是指在应用程序不同模块中的某一个领域或方面。又pointcut 和advice组成。

Weaving

把切面应用到目标对象来创建新的 advised 对象的过程。

原理

简单说说 AOP 的设计

  1. 每个 Bean 都会被 JDK 或者 Cglib 代理。取决于是否有接口。
  2. 每个 Bean 会有多个“方法拦截器”。注意:拦截器分为两层,外层由 Spring 内核控制流程,内层拦截器是用户设置,也就是 AOP。
  3. 当代理方法被调用时,先经过外层拦截器,外层拦截器根据方法的各种信息判断该方法应该执行哪些“内层拦截器”。内层拦截器的设计就是职责连的设计。

流程

代理的创建(按步骤):

  • 首先,需要创建代理工厂,代理工厂需要 3 个重要的信息:拦截器数组,目标对象接口数组,目标对象。
  • 创建代理工厂时,默认会在拦截器数组尾部再增加一个默认拦截器 —— 用于最终的调用目标方法。
  • 当调用 getProxy 方法的时候,会根据接口数量大余 0 条件返回一个代理对象(JDK or Cglib)。
  • 注意:创建代理对象时,同时会创建一个外层拦截器,这个拦截器就是 Spring 内核的拦截器。用于控制整个 AOP 的流程。

代理的调用

  • 当对代理对象进行调用时,就会触发外层拦截器。
  • 外层拦截器根据代理配置信息,创建内层拦截器链。创建的过程中,会根据表达式判断当前拦截是否匹配这个拦截器。而这个拦截器链设计模式就是职责链模式。
  • 当整个链条执行到最后时,就会触发创建代理时那个尾部的默认拦截器,从而调用目标方法。最后返回。

SpringMCC临时用的

https://zhuanlan.zhihu.com/p/62562499

设置属性

1
2
3
4
5
6
7
8
9
// 1. 设置属性
// Make web application context available
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());

// Make locale resolver available
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);

// Make theme resolver available
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);

根据 Request 请求的 URL 得到对应的 handler 执行链,其实就是拦截器和 Controller 代理对象

1
2
// 2. 找 handler 返回执行链
HandlerExecutionChain mappedHandler = getHandler(request);

得到 handler 的适配器

1
2
3
// This will throw an exception if no adapter is found
// 3. 返回 handler 的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

循环执行 handler 的 pre 拦截器

1
2
3
4
5
6
7
8
// 4. 循环执行 handler 的 pre 拦截器
for (int i = 0; i < mappedHandler.getInterceptors().length; i++) {
HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
// pre 拦截器
if (!interceptor.preHandle(request, response, mappedHandler.getHandler())) {
return;
}
}

执行真正的 handler,并返回 ModelAndView(Handler 是个代理对象,可能会执行 AOP )

1
2
// 5. 执行真正的 handler,并返回  ModelAndView(Handler 是个代理对象,可能会执行 AOP )
ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());

循环执行 handler 的 post 拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 6. 循环执行 handler 的 post 拦截器
for (int i = mappedHandler.getInterceptors().length - 1; i >=0 ; i--) {
HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
// post 拦截器
interceptor.postHandle(request, response, mappedHandler.getHandler());
}

# 根据 ModelAndView 信息得到 View 实例
View view = null;
if (mv.isReference()) {
// We need to resolve this view name
// 7. 根据 ModelAndView 信息得到 View 实例
view = this.viewResolver.resolveViewName(mv.getViewName(), locale);
}

# 渲染 View 返回
// 8. 渲染 View 返回
view.render(mv.getModel(), request, response);

其实理解这些才是最重要的。

  1. 用户发送请求至前端控制器DispatcherServlet
  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器。
  3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
  4. DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
  5. HandlerAdapter执行处理器(handler,也叫后端控制器)。
  6. Controller执行完成返回ModelAndView
  7. HandlerAdapter将handler执行结果ModelAndView返回给DispatcherServlet
  8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  9. ViewReslover解析后返回具体View对象
  10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
  11. DispatcherServlet响应用户

Springboot 启动流程

https://juejin.im/post/6844903669998026759

通过 SpringFactoriesLoader 加载 META-INF/spring.factories 文件,获取并创建 SpringApplicationRunListener 对象

然后由 SpringApplicationRunListener 来发出 starting 消息

创建参数,并配置当前 SpringBoot 应用将要使用的 Environment

完成之后,依然由 SpringApplicationRunListener 来发出 environmentPrepared 消息

创建 ApplicationContext

初始化 ApplicationContext,并设置 Environment,加载相关配置等

SpringApplicationRunListener 来发出 contextPrepared 消息,告知SpringBoot 应用使用的 ApplicationContext 已准备OK

将各种 beans 装载入 ApplicationContext,继续由 SpringApplicationRunListener 来发出 contextLoaded 消息,告知 SpringBoot 应用使用的 ApplicationContext 已装填OK

refresh ApplicationContext,完成IoC容器可用的最后一步

SpringApplicationRunListener 来发出 started 消息

完成最终的程序的启动

SpringApplicationRunListener 来发出 running 消息,告知程序已运行起来了

静态变量注入

1
2
3
4
application.properties中配置下面两个配置项
ccb.ip.address=10.25.177.31
ccb.ip.port=1600
下面问题代码中读取不到application.properties配置文件中的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
public class BISFrontFileUtil {
private static Logger logger = LoggerFactory.getLogger(BISFrontFileUtil.class);

private static String CCBIPADDRESS;

private static int CCBIPPORT;

@Value("${ccb.ip.address}")
public void setCCBIPADDRESS(String cCBIPADDRESS) {
CCBIPADDRESS = cCBIPADDRESS;
}

@Value("${ccb.ip.port}")
public void setCCBIPPORT(int cCBIPPORT) {
CCBIPPORT = cCBIPPORT;
}
}

注意:

  1. 修正代码中的@Component不可丢掉了
  2. set方法要是非静态的

SpringBoot的注解

@Configuration

配置并启动Spring容器

@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的,作用为:配置spring容器(应用上下文)

1
2
3
4
5
6
7
8
9
import org.springframework.context.annotation.Configuration;

@Configuration
public class TestConfig {

public TestConfig(){
System.out.println("testconfig collection init success");
}
}

相当于

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd" default-lazy-init="false">

</beans>

主方法进行测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

public static void main(String[] args) {
// @Configuration注解的spring容器加载方式,用AnnotationConfigApplicationContext替换ClassPathXmlApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);

// 如果加载spring-context.xml文件:
// ApplicationContext context = new
// ClassPathXmlApplicationContext("spring-context.xml");
}
}

// 结果
WARNING: All illegal access operations will be denied in a future release
testconfig collection init success

Process finished with exit code 0

@Configuration启动容器+@Bean注册Bean

@Bean标注在方法上(返回某个实例的方法),等价于spring的xml配置文件中的,作用为:注册bean对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Configuration
public class TestConfig {

public TestConfig(){
System.out.println("testconfig collection init success");
}

// @Bean注解注册bean,同时可以指定初始化和销毁方法
// @Bean(name="testBean",initMethod="start",destroyMethod="cleanup")
//name属性相当于<bean>标签的id
@Bean
@Scope("prototype")
public TestBean testBean() {
return new TestBean();
}
}

class TestBean {

private String username;
private String url;
private String password;

public void sayHello() {
System.out.println("TestBean sayHello...");
}

public void start() {
System.out.println("TestBean init...");
}

public void cleanup() {
System.out.println("TestBean destroy...");
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Main {

public static void main(String[] args) {
// @Configuration注解的spring容器加载方式,用AnnotationConfigApplicationContext替换ClassPathXmlApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);
System.out.println(context);

// 如果加载spring-context.xml文件:
// ApplicationContext context = new
// ClassPathXmlApplicationContext("spring-context.xml");

//获取bean
TestBean testBean = (TestBean) context.getBean("testBean");
testBean.sayHello();
}
}

// 结果
结果:
testconfig collection init success
TestBean sayHello...
  • @Bean注解在返回实例的方法上,如果未通过@Bean指定bean的名称,则默认与标注的方法名相同(第一个单词转小写)
  • @Bean注解默认作用域为单例singleton作用域,可通过@Scope(“prototype”)设置为原型作用域
  • 既然@Bean的作用是注册bean对象,那么完全可以使用@Component、@Controller、@Service、@Ripository等注解注册bean,当然需要配置@ComponentScan注解进行自动扫描

scope属性1).  singleton属性值(掌握):默认值,单例2). prototype属性值(掌握):多例(原型作用域)3). request属性值(了解):创建对象,把对象放到request域里4). session属性值(了解):创建对象,把对象放到session域里5). globalSession属性值(了解):创建对象,把对象放到globalSession域里

@Bean下管理bean的生命周期

1
2
3
4
5
6
7
// 用上面的例子
//@Bean注解注册bean,同时可以指定初始化和销毁方法
@Bean(name="testBean",initMethod="start",destroyMethod="cleanUp")
@Scope("prototype")
public TestBean testBean() {
return new TestBean();
}

测试类

1
2
3
4
5
// 结果
testconfig collection init success
org.springframework.context.annotation.AnnotationConfigApplicationContext@41975e01, started on Mon Jul 19 09:51:42 PST 2021
TestBean init...
TestBean sayHello...

@Configuration启动容器+@Component注册Bean

bean类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//添加注册bean的注解
@Component
public class TestBean {

private String username;
private String url;
private String password;

public void sayHello() {
System.out.println("TestBean sayHello...");
}

public void start() {
System.out.println("TestBean init...");
}

public void cleanup() {
System.out.println("TestBean destroy...");
}
}

配置类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Configuration
//添加自动扫描注解,basePackages为TestBean包路径
@ComponentScan(basePackages = "com.example.demo.spring2")
public class TestConfig {

public TestConfig(){
System.out.println("testconfig collection init success");
}

// @Bean注解注册bean,同时可以指定初始化和销毁方法
// @Bean(name="testBean",initMethod="start",destroyMethod="cleanup")
//// @Bean
// @Scope("prototype")
// public TestBean testBean() {
// return new TestBean();
// }
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Main {

public static void main(String[] args) {
// @Configuration注解的spring容器加载方式,用AnnotationConfigApplicationContext替换ClassPathXmlApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);

// 如果加载spring-context.xml文件:
// ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");

//获取bean
TestBean testBean1 = (TestBean) context.getBean("testBean");
testBean1.sayHello();
}
}

// 结果
testconfig collection init success
TestBean sayHello...

AnnotationConfigApplicationContext 注册 AppContext 类的两种方法

第一种:

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {

// @Configuration注解的spring容器加载方式,用AnnotationConfigApplicationContext替换ClassPathXmlApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);

//获取bean
TestBean tb = (TestBean) context.getBean("testBean");
tb.sayHello();
}

第二种:

1
2
3
4
5
6
7
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(TestConfig.class);
annotationConfigApplicationContext.refresh();
}
}

@Configuration组合xml

配置类

1
2
3
4
5
6
7
8
@Configuration
@ImportResource("classpath:configtest.xml")
public class WebConfig {

public WebConfig(){
System.out.println("WebConfig coolection init success");
}
}

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class TestBean2 {

private String username;
private String url;
private String password;

public void setUsername(String username) {
this.username = username;
}

public void setUrl(String url) {
this.url = url;
}

public void setPassword(String password) {
this.password = password;
}

public void sayHello() {
System.out.println("TestBean2 sayHello..."+username);
}

public void start() {
System.out.println("TestBean2 init...");
}

public void cleanUp() {
System.out.println("TestBean2 destroy...");
}
}

spring的xml配置文件

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="testBean2" class="com.example.demo.spring3.TestBean2">
<property name="username" value="ranjun"/>
</bean>
</beans>

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class TestMain2 {

public static void main(String[] args) {
// @Configuration注解的spring容器加载方式,用AnnotationConfigApplicationContext替换ClassPathXmlApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);

// 如果加载spring-context.xml文件:
// ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");

// 获取bean
TestBean2 tb = (TestBean2) context.getBean("testBean2");
tb.sayHello();
}
}

// 结果
WebConfig coolection init success
TestBean2 sayHello...ranjun

@Configuration组合xml和其它注解

实体类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class TestBean {

private String username;
private String url;
private String password;

public void sayHello() {
System.out.println("TestBean sayHello...");
}

public void start() {
System.out.println("TestBean init...");
}

public void cleanup() {
System.out.println("TestBean destroy...");
}
}

public class TestBean2 {

private String username;
private String url;
private String password;

public void setUsername(String username) {
this.username = username;
}

public void setUrl(String url) {
this.url = url;
}

public void setPassword(String password) {
this.password = password;
}

public void sayHello() {
System.out.println("TestBean2 sayHello..."+username);
}

public void start() {
System.out.println("TestBean2 init...");
}

public void cleanUp() {
System.out.println("TestBean2 destroy...");
}
}

配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Configuration
public class TestConfig {

public TestConfig(){
System.out.println("testconfig collection init success");
}

@Bean
@Scope("prototype")
public TestBean testBean() {
return new TestBean();
}
}

@Configuration
@ImportResource("classpath:configtest.xml")
@Import(TestConfig.class)
public class WebConfig {

public WebConfig(){
System.out.println("WebConfig coolection init success");
}
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class TestMain2 {

public static void main(String[] args) {
// @Configuration注解的spring容器加载方式,用AnnotationConfigApplicationContext替换ClassPathXmlApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);

// 获取bean
TestBean tb = (TestBean) context.getBean("testBean");
tb.sayHello();

TestBean2 tb2 = (TestBean2) context.getBean("testBean2");
tb2.sayHello();
}
}

// 结果
WebConfig coolection init success
testconfig collection init success
TestBean sayHello...
TestBean2 sayHello...ranjun