tomcat中request对象是被创建的_常用开源框架中设计模式使用分析(全)
一、前言
說起來設(shè)計(jì)模式,大家應(yīng)該都耳熟能詳,設(shè)計(jì)模式代表了軟件設(shè)計(jì)的最佳實(shí)踐,是經(jīng)過不斷總結(jié)提煉出來的代碼設(shè)計(jì)經(jīng)驗(yàn)的分類總結(jié),這些模式或者可以簡化代碼,或者可以是代碼邏輯開起來清晰,或者對功能擴(kuò)展很方便...。
設(shè)計(jì)模式按照使用場景可以分為三大類:創(chuàng)建型模式(Creational Patterns)、結(jié)構(gòu)型模式(Structural Patterns)、行為型模式(Behavioral Patterns)。
- 創(chuàng)建型模式(Creational Patterns)
- 對對象的實(shí)例化過程進(jìn)行抽象,這使得一個(gè)系統(tǒng)可以不用關(guān)心這些對象是如何創(chuàng)建,組合,呈現(xiàn)的,對于類創(chuàng)建模式來說通過使用繼承改變實(shí)例化的類,對于對象創(chuàng)建模式來說通過使用代理來實(shí)例化所需要的對象。
- 結(jié)構(gòu)型模式(Structural Patterns)
- 通過對多個(gè)類和對象進(jìn)行組合得到復(fù)雜結(jié)構(gòu)的類,一般使用繼承繼承或者成員變量引用形式來實(shí)現(xiàn)。
- 行為型模式(Behavioral Patterns)
- 行為模式不僅表達(dá)了對象和類,還表達(dá)了他們之間的交互,涉及到了對象和算法的分配。
image.png
下面就帶大家看下開源框架框架中是如何應(yīng)用這些經(jīng)典設(shè)計(jì)模式的。
二、責(zé)任鏈設(shè)計(jì)模式(Chain of Responsibility Pattern)
2.1 介紹
責(zé)任鏈模式是把多個(gè)對象串聯(lián)起來形成一個(gè)鏈狀結(jié)構(gòu),讓每個(gè)對象都有機(jī)會對事件發(fā)送者的請求進(jìn)行處理。責(zé)任鏈模式是設(shè)計(jì)模式中的行為模式,設(shè)計(jì)意圖是為了使事件發(fā)送者和事件接受者之間解耦。通常責(zé)任鏈鏈中的每個(gè)對象都有下一個(gè)對象的引入(例如tomcat 里面StandardPipeline用來管理valve),或者有個(gè)同一個(gè)鏈管理工廠里面使用數(shù)組存放了所有的對象(例如tomcat里面ApplicationFilterChain用來關(guān)系filter)。
2.2 Tomcat中Valve鏈
Tomcat中StandardEngine,StandardHost,StandardContext里面都有自己StandardPipeline,下面以StandardEngine里面StandardPipeline為例講解
image.png
從上面類圖可知道每個(gè)Valve都要繼承ValveBase類,該類里面有一個(gè)Valve的引用,實(shí)際是鏈中下一個(gè)節(jié)點(diǎn)對象,Valve就是通過每個(gè)Valve里面的next串聯(lián)為鏈的。
image.png
每個(gè)valve的invoke方法里面調(diào)用next.invoke激活鏈中下一個(gè)節(jié)點(diǎn),并且StandardEngine,StandardHost,StandardContext都有一個(gè)basic valve這個(gè)valve在鏈的末尾用來激活子容器的valve鏈。
2.3 Tomcat中Filter鏈
Tomcat中Filter鏈?zhǔn)鞘褂肁pplicationFilterChain來管理的,具體結(jié)構(gòu)如下圖:
image.png
可知Filter鏈不是像Valve一樣在內(nèi)部維護(hù)下個(gè)節(jié)點(diǎn)的引用,而是在ApplicationFilterChain中搞了個(gè)數(shù)組存放所有的Filter,并通過n統(tǒng)計(jì)Filter總個(gè)數(shù),pos是當(dāng)前filter的下標(biāo)。
ApplicationFilterChain的doFilter代碼如下:
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { ... internalDoFilter(request,response); ... }private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { // Call the next filter if there is one if (pos < n) { //獲取filter鏈中下標(biāo)為pos的filter ApplicationFilterConfig filterConfig = filters[pos++]; Filter filter = null; try { filter = filterConfig.getFilter(); support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT, filter, request, response); if (request.isAsyncSupported() && "false".equalsIgnoreCase( filterConfig.getFilterDef().getAsyncSupported())) { request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE); } ... //調(diào)用自定義filter的dofilter方法 filter.doFilter(request, response, this); support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, request, response); } .... } .....}注:這兩種方式的區(qū)別是啥,就是說那些場景下使用2.2,什么情況下使用2.3這個(gè)目前還沒有搞清楚有
知道的麻煩在本帖留言幫我解惑下^^
2.4 使用場景
- 當(dāng)一個(gè)請求需要
- 根據(jù)請求參數(shù)的不同由不同對象來處理時(shí)候。
- 當(dāng)一個(gè)請求需要固定對象順序處理,并且可擴(kuò)展性的在固定順序里面插入新的對象進(jìn)行處理時(shí)候。
三、工廠模式(Factory Pattern)
3.1 介紹
工廠模式是創(chuàng)建型模式,他封裝了對象的創(chuàng)建過程,調(diào)用者使用具體的工廠方法根據(jù)參數(shù)就可以獲取對應(yīng)的對象。
3.2 Spring框架中BeanFactory
image.png
如圖BeanFactory接口提供了getBean方法,在AbstractBeanFactory中實(shí)現(xiàn)了該方法,經(jīng)過層層繼承,實(shí)現(xiàn),最后DefaultListableBeanFactory實(shí)現(xiàn)了BeanDefinitionRegistry接口用來保存bean定義,繼承了AbstractAutowireCapableBeanFactory用來支撐autowired。
一個(gè)例子
@Testpublic void testBeanFactoy() throws NamingException, SQLException, ParseException, IOException { //創(chuàng)建Bean工廠 DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); //給bean工廠添加bean定義,解析xml里面的bean放入bean工廠 loadBeanDefinitions(bf); //根據(jù)名字從bean工廠獲取bean Hello hello = (Hello) bf.getBean("hello"); hello.sayHello(); Hello2 hello2 = (Hello2) bf.getBean("hello2"); hello2.sayHello(); }protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); String[] configLocations = new String[] { "beans2.xml" }; if (configLocations != null) { beanDefinitionReader.loadBeanDefinitions(configLocations); }}3.3 使用場景
- 不同條件下創(chuàng)建不同實(shí)例,用于統(tǒng)一管理bean
- 不同條件下調(diào)用不同工廠方法獲取不同場景下的bean
四、單例設(shè)計(jì)模式(Singleton Pattern)
4.1 介紹
單例模式是一種創(chuàng)建型模式,單例模式提供一個(gè)創(chuàng)建對象的接口,但是多次調(diào)用該接口返回的是同一個(gè)實(shí)例的引用,目的是為了保證只有一個(gè)實(shí)例,并且提供一個(gè)訪問這個(gè)實(shí)例的統(tǒng)一接口。
4.2 Spring中單例bean的創(chuàng)建
Spring中默認(rèn)配置的bean的scope為singleton,也就是單例作用域。那么看看它是如何做到的。
在AbstractBeanFactory類里面的doGetBean方法:
protected Object doGetBean( final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean = null; // 解決set循環(huán)依賴 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { ... } else { ... // 創(chuàng)建單件bean. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory() { public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { ... throw ex; } } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } //創(chuàng)建原型bean else if (mbd.isPrototype()) { ... } //創(chuàng)建request作用域bean else { ... } } ... return bean;}getSingleton代碼:
public Object getSingleton(String beanName, ObjectFactory singletonFactory) { Assert.notNull(beanName, "'beanName' must not be null"); synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { ... beforeSingletonCreation(beanName); ... try { singletonObject = singletonFactory.getObject(); } catch (BeanCreationException ex) { ... } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } afterSingletonCreation(beanName); } addSingleton(beanName, singletonObject); } return (singletonObject != NULL_OBJECT ? singletonObject : null); }}protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT)); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); }}private final Map singletonObjects = CollectionFactory.createConcurrentMapIfPossible(16);可知Spring內(nèi)部四通過一個(gè)ConcurrentMap來管理單件bean的。獲取bean時(shí)候會先看看singletonObjects中是否有,有則直接返回,沒有則創(chuàng)建后放入。
看個(gè)時(shí)序圖:
image.png
Spring的bean工廠管理的單例模式管理的是多個(gè)bean實(shí)例的單例,是工廠模式管理所有的bean,而每個(gè)bean的創(chuàng)建又使用了單例模式。
4.4 使用場景
- 同一個(gè)jvm應(yīng)用的不同模塊需要使用同一個(gè)對象實(shí)例進(jìn)行信息共享。
- 需要同一個(gè)實(shí)例來生成全局統(tǒng)一的序列號
五、原型設(shè)計(jì)模式(Prototype Pattern)
5.1 介紹
相比單例設(shè)計(jì)模式,原型模式是每次創(chuàng)建一個(gè)對象,下面看下spring是如何使用原型模式的
5.2 Spring中原型bean的創(chuàng)建
創(chuàng)建原型bean需要在xml特別說明:
protected T doGetBean( final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; // Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { ... } else { ... try { ... // Create bean instance. if (mbd.isSingleton()) { ... } //創(chuàng)建原型bean 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 { ... } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } ... return (T) bean;}createBean函數(shù)里面則是根據(jù)bean定義創(chuàng)建新bean,感興趣的可以看看。
5.3 使用場景
- 當(dāng)有業(yè)務(wù)場景使用某個(gè)bean時(shí)候需要使用自己的一個(gè)拷貝的時(shí)候使用。
六、 策略模式(Strategy Pattern)
6.1 介紹
策略模式屬于行為性模式,它定義一系列的算法對象,使用時(shí)候可以使它們相互替換。
6.2 Spring中bean實(shí)例化策略
首先看下類圖:
image.png
從圖知道:接口InstantiationStrategy是實(shí)例化策略接口類,它定義了三個(gè)實(shí)例化接口,然后SimpleInstantiationStrategy實(shí)現(xiàn)了該策略,它主要做一些簡單的根據(jù)構(gòu)造函數(shù)實(shí)例號bean的工作,然后CglibSubclassingInstantiationStrategy又繼承了SimpleInstantiationStrategy新增了方法注入方式根據(jù)cglib生成代理類實(shí)例化方法。
在AbstractAutowireCapableBeanFactory中管理了該策略的一個(gè)對象,默認(rèn)是CglibSubclassingInstantiationStrategy策略,運(yùn)行時(shí)候可以通過setInstantiationStrategy改變實(shí)例化策略,如果你自己寫個(gè)個(gè)策略的話。
6.3 Spring中Aop代理策略
image.png
首先看AopProxyFactory接口類提供了createAopProxy接口,這個(gè)是策略模式的接口方法。然后DefaultAopProxyFactory實(shí)現(xiàn)了該接口作為策略的實(shí)現(xiàn)者。然后ProxyCreatorSupport里面引用了AopProxyFactory,并且提供了get,set方法用來運(yùn)行時(shí)改變策略,這里Spring只實(shí)現(xiàn)了DefaultAopProxyFactory這一個(gè)策略,如果需要自己也可以寫個(gè)。
DefaultAopProxyFactory里面的createAopProxy的邏輯如下,可以在運(yùn)行時(shí)根據(jù)參數(shù)決定用Cglib策略還是JDK動態(tài)代理策略生成代理類:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { //如果XML打開了優(yōu)化開關(guān),或者設(shè)置為了代理目標(biāo)類,或者目前類沒有接口 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } //如果有接口,或者通過Proxy.newProxyInstance生成的,則使用jdk動態(tài)代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } //使用cglib return new ObjenesisCglibAopProxy(config); } else { //使用jdk動態(tài)代理 return new JdkDynamicAopProxy(config); } }另外AopProxy也是一個(gè)策略接口類,具體實(shí)現(xiàn)的策略為JdkDynamicAopProxy,CglibAopProxy,ObjenesisCglibAopProxy
6.4 Tomcat中Digester解析server.xml
tomcat中的Digester是為了解析server.xml的,其中每個(gè)元素都有一個(gè)解析規(guī)則就是Rule ,類圖如下:
DigestER一開始先指定不同的解析策略(Rule),然后在具體解析Server.xml時(shí)候根據(jù)節(jié)點(diǎn)不同使用不同解析策略來解析節(jié)點(diǎn)。
image.png
如圖在解析每個(gè)節(jié)點(diǎn)時(shí)候會先找到該節(jié)點(diǎn)對應(yīng)的解析策略,然后循環(huán)去調(diào)用所有解析策略的方法去處理。
6.5 使用場景
- 運(yùn)行時(shí)根據(jù)條件的不同使用不同的策略處理一個(gè)事情,與責(zé)任鏈不同在于,責(zé)任鏈?zhǔn)且粋€(gè)鏈條,一個(gè)事情可以被責(zé)任鏈里面所有節(jié)點(diǎn)處理,而 策略模式則是只有有一個(gè)對象來處理。
七、 門面模式(Facade Pattern)
7.1 介紹
門面模式是一種結(jié)構(gòu)性模式,它通過新增一個(gè)門面類對外暴露系統(tǒng)提供的一部分功能,或者屏蔽了內(nèi)部系統(tǒng)的復(fù)雜性,對外部僅僅暴露一個(gè)簡單的接口,或者通過調(diào)用不同的服務(wù)對外提供統(tǒng)一的接口,讓使用者對這些內(nèi)部服務(wù)透明化。
7.2 模板引擎Velocity中門面模式使用
Velocity里面的VelocityEngine和Velocity類都是RuntimeInstance類的門面,后者提供了模板渲染的所有功能,前兩者則是內(nèi)部維護(hù)RuntimeInstance的實(shí)例,具體工作還是委托給RuntimeInstance來實(shí)現(xiàn)。
關(guān)于Veloctiy可以參考:https://www.atatech.org/articles/78435
image.png
如圖 RuntimeInstance提供了Velocity引擎的所用功能,VelocityEngine內(nèi)部直接引用了RuntimeInstance的一個(gè)實(shí)例,VelocityEngine對外暴露的服務(wù)都是委托RuntimeInstance實(shí)現(xiàn),并且每次new一個(gè)VelocityEngine內(nèi)部都會有RuntimeInstance的一個(gè)實(shí)例被創(chuàng)建。而Velocity類調(diào)用了單例模式類RuntimeSingleton里面的方法,RuntimeSingleton又是RuntimeInstance的一個(gè)單例模式。
7.3 使用場景
- 當(dāng)需要對外屏蔽一個(gè)系統(tǒng)的復(fù)雜性時(shí)候可以考慮使用門面模式對外提供簡單可讀性高的接口類
- 當(dāng)需要對外部暴露系統(tǒng)一部分權(quán)限的接口時(shí)候可以考慮使用門面模式減少系統(tǒng)權(quán)限。
- 當(dāng)系統(tǒng)需要調(diào)用不同服務(wù)匯總后在對外提供服務(wù)時(shí)候可以考慮使用門面模式對外屏蔽細(xì)節(jié),之暴露一個(gè)接口。
九、裝飾器模式(Decorator Pattern)
9.1 介紹
裝飾器模式是一種結(jié)構(gòu)性模式,它作用是對對象已有功能進(jìn)行增強(qiáng),但是不改變原有對象結(jié)構(gòu)。這避免了通過繼承方式進(jìn)行功能擴(kuò)充導(dǎo)致的類體系臃腫。
9.2 Spring中BeanDefinitionDecorator
先看下類圖:
image.png
如圖ScopedProxyBeanDefinitionDecorator實(shí)現(xiàn)了decorate方法用來對scope作用域?yàn)閞equest的bean定義進(jìn)行包裝。
具體時(shí)序圖為:
image.png
class ScopedProxyBeanDefinitionDecorator implements BeanDefinitionDecorator { private static final String PROXY_TARGET_CLASS = "proxy-target-class"; @Override public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { boolean proxyTargetClass = true; if (node instanceof Element) { Element ele = (Element) node; if (ele.hasAttribute(PROXY_TARGET_CLASS)) { proxyTargetClass = Boolean.valueOf(ele.getAttribute(PROXY_TARGET_CLASS)); } } // 創(chuàng)建scoped的代理類,并注冊到容器 BeanDefinitionHolder holder = ScopedProxyUtils.createScopedProxy(definition, parserContext.getRegistry(), proxyTargetClass); String targetBeanName = ScopedProxyUtils.getTargetBeanName(definition.getBeanName()); parserContext.getReaderContext().fireComponentRegistered( new BeanComponentDefinition(definition.getBeanDefinition(), targetBeanName)); return holder; }}關(guān)于ScopedProxyBeanDefinitionDecorator干啥用的那:
其實(shí)就是處理
的,具體作用是包裝lavaPvgInfo的bean定義為ScopedProxyFactoryBean,作用是實(shí)現(xiàn)request作用域bean.
9.3 commons-collections包中ListUtils
image.png
如圖
ListUtils中的四個(gè)方法分別依賴list的四種裝飾器類對List功能進(jìn)行擴(kuò)充和限制。
其中FixedSizeList類通過禁止add/remove操作保證list的大小固定,但是可以修改元素內(nèi)容
其中UnmodifiableList類通過禁用add,clear,remove,set,保證list的內(nèi)容不被修改
其中SynchronizedList類通過使用Lock 來保證add,set,get,remove等的同步安全
其中LazyList類則當(dāng)調(diào)用get方法發(fā)現(xiàn)list里面不存在對象時(shí)候,自動使用factory創(chuàng)建對象.
9.4 使用場景
- 在不改變原有類結(jié)構(gòu)基礎(chǔ)上,新增或者限制或者改造功能時(shí)候。
十、適配器模式(Adapter Pattern)
10.1 介紹
適配器模式屬于結(jié)構(gòu)性模式,它為兩個(gè)不同接口之間互通提供了一種手段。
10.2 Spring中MethodInterceptor適配器
在Spring Aop框架中,MethodInterceptor接口被用來攔截指定的方法,對方法進(jìn)行增強(qiáng)。
image.png
大家都知道在Aop中每個(gè)advistor 里面會有一個(gè)advice具體做切面動作,Spring提供了AspectJAfterReturningAdvice,AspectJMethodBeforeAdvice,AspectJAroundAdvice,AspectJAfterAdvice這幾個(gè)advice,在XML 配置aop時(shí)候會指定,,,,其實(shí)內(nèi)部就是創(chuàng)建上面對應(yīng)的這些advice。
從圖知道AspectJAfterReturningAdvice和AspectJMethodBeforeAdvice沒有實(shí)現(xiàn)MethodInterceptor接口,其他兩者則實(shí)現(xiàn)了該接口。而Spring Aop的方法攔截器卻必須是實(shí)現(xiàn)了MethodInterceptor的,所以Spring提供了對應(yīng)的適配器來適配這個(gè)問題,分別是MethodBeforeAdviceAdapter和AfterReturningAdviceAdapter和ThrowsAdviceAdapter。
image.png
看下DefaultAdvisorAdapterRegistry的 getInterceptors方法:
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List interceptors = new ArrayList(3); //從advistor中獲取advice Advice advice = advisor.getAdvice(); //如果實(shí)現(xiàn)了MethodInterceptor則直接加入,比如AspectJAroundAdvice,AspectJAfterAdvice if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } //否者看是否有當(dāng)前advice的適配器,首先檢驗(yàn)是否支持,支持則返回對應(yīng)的適配器 for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor[interceptors.size()]);}以MethodBeforeAdviceAdapter為例子看下:
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable { public boolean supportsAdvice(Advice advice) { return (advice instanceof MethodBeforeAdvice); } public MethodInterceptor getInterceptor(Advisor advisor) { MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); return new MethodBeforeAdviceInterceptor(advice); }}public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable { private MethodBeforeAdvice advice; /** * Create a new MethodBeforeAdviceInterceptor for the given advice. * @param advice the MethodBeforeAdvice to wrap */ public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); return mi.proceed(); }}可知MethodBeforeAdviceInterceptor繼承了MethodInterceptor作為了一個(gè)適配器內(nèi)部委托請求給MethodBeforeAdvice。
10.3 使用場景
- 兩個(gè)系統(tǒng)交互時(shí)候由于接口參數(shù)不一樣沒辦法直接對接,則可以搞個(gè)適配器接口做參數(shù)轉(zhuǎn)換。
- 適配器模式經(jīng)常是在一個(gè)系統(tǒng)或者設(shè)計(jì)已經(jīng)定型時(shí)候用的,而不是在初始設(shè)計(jì)時(shí)候。一般是因?yàn)椴挥绊懍F(xiàn)在業(yè)務(wù)情況下,通過適配方式統(tǒng)一接口
十一、模板設(shè)計(jì)模式(Template Pattern)
11.1 前言
模板設(shè)計(jì)模式是一種行為設(shè)計(jì)模式,它使用一個(gè)抽象類定義了一個(gè)模板,這個(gè)模板里面定義了一系列的接口,子類則只需要繼承該抽象類并且根據(jù)需要重寫一部分接口。
11.2 ibatis2中AbstractDAOTemplate
image.png
如圖AbstractDAOTemplate是抽象模板類,里面定義了configure方法,configure方法里面定義了好多protected方法,其中就有些是抽象方法。類SpringDAOTemplate,IbatisDAOTemplate,GenericCIDAOTemplate,GenericSIDAOTemplate則繼承了AbstractDAOTemplate類并重寫了一部分方法。
11.3 Tomcat中Digester里面的Rule
tomcat中的Digester是為了解析server.xml的,其中每個(gè)元素都有一個(gè)解析規(guī)則就是Rule ,類圖如下:
image.png
如圖:Rule是抽象類,對于每個(gè)解析的節(jié)點(diǎn)來說Rule提供了解析所需所有的方法,而他的子類則根據(jù)自己的特殊性重寫一部分方法來支持自己的特性。
11.4 Tomcat中Endpoint
image.png
如圖AbstractEndpoint是個(gè)抽象類,定義了Endpoint的所有接口,然后JIoEndpoint繼承了該類并且重寫了一部分重要的方法實(shí)現(xiàn)了BIO方式endpoint,NioEndpoint則重寫了方法實(shí)現(xiàn)了NIO的endpoint.
11.5使用場景
- 當(dāng)多個(gè)子類具有共同的操作流程邏輯,并且其中某些流程節(jié)點(diǎn)操作需要自己定制化時(shí)候。
十二、 建造者模式(Builder Pattern)
12.1 前言
建造者模式是一種創(chuàng)建型模式,將一個(gè)復(fù)制對象的創(chuàng)建屏蔽到接口內(nèi)部,用戶使用時(shí)候只需要傳遞固定的參數(shù),內(nèi)部就會執(zhí)行復(fù)雜邏輯后返回會用戶需要的對象,用戶不需要知道創(chuàng)建的細(xì)節(jié)。
12.2 Mybatis中的SqlSessionFactoryBuilder
image.png
如圖mybaits中的SqlSessionFactoryBuilder就是典型的創(chuàng)建者模式,他內(nèi)部有多個(gè)build方法,根據(jù)參數(shù)的不同創(chuàng)建出SqlSessionFactory對象,使用者只需要傳遞具體參數(shù)而不用關(guān)系內(nèi)部是如何創(chuàng)建出需要的對象的。SqlSessionFactoryBean大家應(yīng)該很熟悉,在xml里面配置的。
12.3 使用場景
- 當(dāng)一個(gè)對象比較復(fù)雜并且容易出錯(cuò)時(shí)候,可以考慮這種模式去屏蔽創(chuàng)造細(xì)節(jié)。
十三、 觀察者模式(Observer Pattern)
13.1 前言
觀察者模式是一種行為模式,它定義了當(dāng)一個(gè)對象的狀態(tài)或者屬性發(fā)生變化時(shí)候,通通知其他對這些狀態(tài)感興趣的對象。觀察者模式也叫發(fā)布-訂閱模式,就是說當(dāng)你訂閱了摸一個(gè)主體時(shí)候,如果發(fā)布者改變了主題內(nèi)容,那么所有訂閱這個(gè)主體者都會受到通知。
13.2 Spring中ApplicationListener
image.png
如圖 黃色部分的listener們可以認(rèn)為是訂閱者,紅色的context是發(fā)布者,context在IOC不同狀態(tài)會給這些訂閱者發(fā)布不同的消息通知訂閱者容器狀態(tài)。藍(lán)色的為具體的事件(這里為容器不同狀態(tài)),其中ContextRefreshedEvent是IOC刷新完成(也就是bean解析完成,創(chuàng)建完畢并且autowired完成)后的事件這個(gè)經(jīng)常用。
。這里context并不是直接來管理黃色的listener訂閱者的,而是委托給了綠色的部分,該部分是可以增加刪除訂閱者,并且發(fā)布事件給訂閱者。
其實(shí)Tomact中的Lifecycle也是這種機(jī)制,這里不再贅述。
13.3 使用場景
- 滿足發(fā)布-訂閱條件的,當(dāng)一個(gè)對象狀態(tài)或者屬性變化,需要把這種變化通知到訂閱者時(shí)候。
十四、命令模式(Command Pattern)
14.1 介紹
命令模式是一種行為模式,通過把命令封裝為一個(gè)對象,命令發(fā)送者把命令對象發(fā)出后,就不去管是誰來接受處理這個(gè)命令,命令接受者接受到命令對象后進(jìn)行處理,也不用管命令是誰發(fā)出的,所以命令模式實(shí)現(xiàn)了發(fā)送者與接受者之間的解耦,而具體把命令發(fā)送給誰還需要一個(gè)控制器。
14.2 Tomcat中命令模式
tomcat作為一個(gè)服務(wù)器本身會接受外部大量請求,當(dāng)一個(gè)請求過來后tomcat根據(jù)域名去找對應(yīng)的host,找到host后會根據(jù)應(yīng)用名去找具體的context(應(yīng)用),然后具體應(yīng)用處理請求。對于具體host來說他不關(guān)心這個(gè)請求是誰給的,對應(yīng)請求來說他不必關(guān)心誰來處理,但是兩者是通過request封裝請求對象進(jìn)行關(guān)聯(lián)起來。
image.png
tomcat中Connector作為命令發(fā)出者,Connector接受到請求后把請求內(nèi)容封裝為request對象(命令對象),然后使用CoyoteAdapter作為分發(fā)器把請求具體發(fā)配到具體的host,host在根據(jù)request對象找到具體的context,至此找到了具體的應(yīng)用,交給具體應(yīng)用處理。
另外對于使用springmvc的應(yīng)用來說,上面找到具體應(yīng)用,但是具體交給那個(gè)controller來處理那,這是不是也是命令模式的使用那。
14.3 使用場景
- 當(dāng)事件發(fā)送者和接受者直接需要完全解耦(直接并不存在引用關(guān)系)時(shí)候。
十五、參考
- http://www.uml.org.cn/c++/pdf/DesignPatterns.pdf
十六、總結(jié)
設(shè)計(jì)模式中每一個(gè)模式都描述了在我們工作中不斷重復(fù)發(fā)生的問題,以及問題的解決方案,所以真正掌握設(shè)計(jì)模式可以避免我們做不必要的重復(fù)勞動。
歡迎關(guān)注微信公眾號:技術(shù)原始積累 獲取更多技術(shù)干貨_
總結(jié)
以上是生活随笔為你收集整理的tomcat中request对象是被创建的_常用开源框架中设计模式使用分析(全)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我和老公的姓,根本组合不到一起,我妈非要
- 下一篇: python 根据地址求经纬度 谷歌_利