Spring源码阅读(八)-设计模式

一、责任链模式

1、DispatcherServlet#doDispatch

在这里插入图片描述
getHandler 方法的处理使用到了责任链模式,handlerMappings 是之前 Spring 容器初始化好的,通过遍历 handlerMappings 查找与 request 匹配的 Handler, 这里返回 HandlerExecutionChain 对象

2、Spring AOP

JdkDynamicAopProxy#invoke()方法核心代码:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

		*******
		
		// 将切面上的通知封装成责任链
		// Get the interception chain for this method.
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

		// Check whether we have any advice. If we don't, we can fallback on direct
		// reflective invocation of the target, and avoid creating a MethodInvocation.
		if (chain.isEmpty()) {
			// We can skip creating a MethodInvocation: just invoke the target directly
			// Note that the final invoker must be an InvokerInterceptor so we know it does
			// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
		}
		else {
			// 通过调用责任链+递归的方式执行
			// We need to create a method invocation...
			invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
			// Proceed to the joinpoint through the interceptor chain.
			retVal = invocation.proceed();
		}
		
		*******
}

二、监听者模式

Spring容器刷新中的AbstractApplicationContext#finishRefresh()方法。
Spring容器已经大致刷新完成,此时会调用AbstractApplicationContext#publishEvent(ApplicationEvent)方法进行上下文刷新完成事件广播,Dubbo的服务暴露就是在此时执行的!

  我们知道,< dubbo:service > 标签会被解析成 ServiceBean,ServiceBean 实现了 ApplicationListener,在 Spring 容器初始化的时候会调用 onApplicationEvent 方法。ServiceBean 重写了 onApplicationEvent 方法,实现了服务暴露的功能。
ServiceBean#onApplicationEvent

public void onApplicationEvent(ContextRefreshedEvent event) {
	if (!isExported() && !isUnexported()) {
		if (logger.isInfoEnabled()) {
			logger.info("The service ready on spring started. service: " + getInterface());
		}
		
		// 暴露服务
		export();
	}
}

三、模板方法模式:

1、AbstractApplicationContext#refresh()

父类AbstractApplicationContext定义了refresh的整个执行流程,而有些模板方法父类已实现,有些并没有实现,这就需要子类去实现。比如AbstractApplicationContext的onRefresh()方法是个空的模板方法,并没有具体的业务逻辑。而在springboot中其子类EmbeddedWebApplicationContext重写了该方法,springboot内置的容器(如Tomcat)正是在此方法中创建的!
先看下类的继承关系:
在这里插入图片描述
接下来再进入TomcatEmbeddedServletContainerFactory#getEmbeddedServletContainer()方法看下Tomcat是如何创建的。

@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
		ServletContextInitializer... initializers) {
	Tomcat tomcat = new Tomcat();
	File baseDir = (this.baseDirectory != null) ? this.baseDirectory
			: createTempDir("tomcat");
	tomcat.setBaseDir(baseDir.getAbsolutePath());
	Connector connector = new Connector(this.protocol);
	tomcat.getService().addConnector(connector);
	customizeConnector(connector);
	tomcat.setConnector(connector);
	tomcat.getHost().setAutoDeploy(false);
	configureEngine(tomcat.getEngine());
	for (Connector additionalConnector : this.additionalTomcatConnectors) {
		tomcat.getService().addConnector(additionalConnector);
	}
	prepareContext(tomcat.getHost(), initializers);
	return getTomcatEmbeddedServletContainer(tomcat);
}
2、JdbcTemplate

四、策略模式

先看下策略模式的UML图:
在这里插入图片描述
  上图中的Strategy接口是策略接口类,StrategyA、StrategyB是具体的策略,而StrategyContext是策略的决策者,由它来指定使用哪个策略。

  Spring的资源访问接口Resource就是策略,而它有多个具体资源访问类,如下:
在这里插入图片描述
那context策略决策者是谁?这个就是我们的ApplicationContext!

public static void main(String[] args) {
	//1、加载配置文件
   ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring.xml");
   //2、通过配置文件获取一个bean并打印
   System.err.println(ctx.getBean("stu").toString());
}

上面代码是我们常用的加载Spring的配置文件的方式,ClassPathXmlApplicationContext它指定了了我们具体用哪个资源实现策略。

ClassPathXmlApplicationContext#ClassPathXmlApplicationContext()

public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, ApplicationContext parent)
		throws BeansException {

	super(parent);
	Assert.notNull(paths, "Path array must not be null");
	Assert.notNull(clazz, "Class argument must not be null");
	this.configResources = new Resource[paths.length];
	for (int i = 0; i < paths.length; i++) {
		// 此处指定了用ClassPathResource策略加载
		this.configResources[i] = new ClassPathResource(paths[i], clazz);
	}
	refresh();
}

ClassPathResource是Resource的子类
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值