往期回顧:
聲明:本文中源碼使用的是Spring5.3版本,就是源碼中的master分支!!!
一般來說,設計模式分為創建型、結構性和行為性,具體的有以下23種,其中的簡單工廠模式其實不算真正意義上的設計模式:
我在看Spring源碼的過程中,梳理出了如下幾種設計模式:
下面詳細介紹每一種設計模式是如何在Spring中使用的,這些知識點不算是閱讀源碼的前置知識點,但是Spring的源碼也不是讀一兩遍就能完全掌握的,我就是一個方法一個方法地通讀了一遍之后,因為讀到了很多不理解的寫法,然后通過查閱資料才發現是用到了這些設計模式,所以整個下來感受就是:知道這些設計模式,對於通讀之后的精讀,掌握Springq其他組件,比如SpringBoot等,甚至是在開發過程中對Spring進行擴展,都算是一個前置條件,而且知道了這些,讀起源碼來,才能自頂向下有一個全局的認識。廢話不多說,直接開寫吧!
一、創建性模式
在Spring中單例和多例都是用來創建bean的時候使用,現來看一下創建bean的代碼:
1.1 單例模式
單例模式詳解傳送門:http://c.biancheng.net/view/1338.html
Spring中的應用:創建Bean
說明:單例模式就是Spring中定義Bean的時候,可以指定scope,如果是Singleton,就會創建在Spring容器內創建一個全局唯一的單例bean,但需要注意的是,spring中的單例跟設計模式中的單例還是有區別的,在設計模式中,相同的類加載器只能創建一個實例,但是在spring中,是通過bean的id來校驗唯一性,就是說,同一個類可以創建多個id不同的實例,spring中創建單例的源代碼如下:
1 // Create bean instance. 2 if (mbd.isSingleton()) { 3 //單例模式:創建單例bean 4 sharedInstance = getSingleton(beanName, () -> { 5 try { 6 return createBean(beanName, mbd, args); 7 } catch (BeansException ex) { 8 /*Explicitly remove instance from singleton cache: It might have been put there 9 eagerly by the creation process, to allow for circular reference resolution. 10 Also remove any beans that received a temporary reference to the bean. 11 1、需要從單例緩存中顯示地移除:因為為了解決循環引用問題可以在早期創建程序中就已經設置到緩存中了 12 2、也要刪除任何指向該bean的臨時引用*/ 13 destroySingleton(beanName); 14 throw ex; 15 } 16 }); 17 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 18 }
上面的第4~7行就是創建一個單例bean的過程,先看getSingleton方法:
其中的singletonObjects的源碼如下:
/** * Cache of singleton objects: bean name to bean instance. * 緩存單例對象:beanName->beanInstance */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
在一個CurrentHashMap中存儲beanName到beanInstance的映射關系,其實這就是傳說中的一級緩存,從代碼可以看出,Spring在創建一個單例bean的時候,會先通過beanName從一級緩存中獲取,當獲取不到是才會去調用回調函數createBean進行實例創建,在createBean中調用doCreateBean,在doCreateBean中調用instantiateBean方法,而instantiateBean具體創建bean的過程是通過策略模式實現的,這個在策略模式中講,但在這里就能感覺到源碼的魅力了。
1.2 原型模式
原型模式詳解傳送門:http://c.biancheng.net/view/1343.html
Spring中的應用:創建Bean
說明:同單例模式,如果指定bean的scope為Prototype,就會創建多例bean,即在每次獲取時都會創建一個bean對象,Spring中創建多例bean的原源代碼如下:
1 if (mbd.isPrototype()) { 2 //多例模式:創建多例bean 3 Object prototypeInstance = null; 4 try { 5 beforePrototypeCreation(beanName); 6 prototypeInstance = createBean(beanName, mbd, args); 7 } finally { 8 afterPrototypeCreation(beanName); 9 } 10 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 11 }
可以看到和單例模式不同的地方在於,在調用createBean之前,沒有調用getSingleton方法從一級緩存中獲取,就是說每次獲取都是創建一個新的。下面用一個例子來驗證單例和多例:
1、在spring.xml中定義兩個bean,一個為單例,一個為多例
1 <bean id="face1" class="com.spring.reading.vo.Face" init-method="init" destroy-method="destroy" scope="singleton"> 2 <property name="eye" value="黑眼睛1"/> 3 </bean> 4 <bean id="face2" class="com.spring.reading.vo.Face" init-method="init" destroy-method="destroy" scope="prototype"> 5 <property name="eye" value="黑眼睛2"/> 6 </bean>
上面第1行定義了一個名稱為face1的bean,它的scope為singleton,第4行定義了一個名稱為face2的bean,它的scope為prototype
2、獲取兩個face1和兩個face2,並比較兩個對象是否相等
1 public class OpenTheDoor { 2 3 public static void main(String[] args) { 4 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-lifecycle.xml"); 5 System.out.println("---獲取單例Bean---"); 6 Face face11 = (Face) context.getBean("face1"); 7 Face face12 = (Face) context.getBean("face1"); 8 System.out.println("face11=face12:" + (face11 == face12)); 9 System.out.println("face11=face12:" + (face11.equals(face12))); 10 System.out.println("---獲取多例Bean---"); 11 Face face21 = (Face) context.getBean("face2"); 12 Face face22 = (Face) context.getBean("face2"); 13 System.out.println("face21=face22:" + (face21 == face22)); 14 System.out.println("face11=face12:" + (face21.equals(face22))); 15 context.close(); 16 } 17 }
上面的第6、7行兩次獲取名稱為face1的Face對象,第11、12行兩次獲取名稱為face2的Face對象,並對兩次獲取的結果進行比較,同時使用了==和equals方法,因為沒有重寫equals方法,所以比較的還是對象在內存中的地址。
3、查看比較結果
可以看出同一個類的不同bean,定義成單例時,每次獲取的都是同一個對象,定義成單例時,每次獲取都是不同的對象,其實這里就能看出Spring中的單例跟設計模式中的單例其實是有區別的,spring中同一個類可以創建多個對象,通過id區分不同實例,通過一個beanName多次獲取對象時,每次都能取到同一個,而在單例模式中,同一個類全局只能創建一個實例對象,雖然都叫單例,但Spring中的單例其實並不是真正意義上的單例模式。
總結:
1、Spring創建Bean時默認是單例模式,且非懶加載,即在容器啟動過程中就完成創建
2、對於同一個類,可以創建不同的實例,每個實例是不相同的,只是根據同一個beanName多次獲取時,得到的實例都是同一個;
3、單例模式中的單例是針對同一個類,全局只能創建一個唯一的實例。
以上就是對Spring中單例模式和多例模式的分析過程。
1.3 工廠模式
工廠模式詳解傳送門:http://c.biancheng.net/view/1351.html
spring中的工廠模式有兩種,一種是工廠方法模式,一種是抽象工廠模式,它們二者的區別在於前者是具體工廠生產具體的產品,而后者是一個工廠中可以生產不同類型的產品,Spring中主要涉及的類和接口如下:
可以看到兩者,一個是BeanFactory,一個是BeanFactory,它們兩者也有一定的區別,簡單來講就是:BeanFactory是spring容器中用來生產bean的工廠,它負責管理一個Bean的生命周期;而FactoryBean它本身就是一個Bean,同時也可以作為工廠來生產各種自定義的Bean,不支持管理Bean的生命周期,需要開發者手動實現實現管理Bean初始化的接口InitializingBean和銷毀的接口DisposableBean,一般用與和第三方集成。
1.4 建造者模式
建造者模式傳送門:http://c.biancheng.net/view/1354.html
Spring中的應用:用來在web應用中提供http請求響應結果
說明:建造者模式指將一個復雜對象的構造與它的表示分離,使同樣的構建過程可以創建不同的表示,這樣的設計模式被稱為建造者模式。它是將一個復雜的對象分解為多個簡單的對象,然后一步一步構建而成。它將變與不變相分離,即產品的組成部分是不變的,但每一部分是可以靈活選擇的。
建造者(Builder)模式的主要角色如下。
- 產品角色(Product):它是包含多個組成部件的復雜對象,由具體建造者來創建其各個零部件。
- 抽象建造者(Builder):它是一個包含創建產品各個子部件的抽象方法的接口,通常還包含一個返回復雜產品的方法 getResult()。
- 具體建造者(Concrete Builder):實現 Builder 接口,完成復雜產品的各個部件的具體創建方法。
- 指揮者(Director):它調用建造者對象中的部件構造與裝配方法完成復雜對象的創建,在指揮者中不涉及具體產品的信息。
spring中各個角色對應的類如下:
二、結構性模式
2.1 代理模式
代理模式傳送門:http://c.biancheng.net/view/1359.html
Spring中的應用:Aop
說明:通過jdk和cglib動態代理方式實現Aop功能
首先來了解一下兩種動態代理的區別:
下面先舉兩種動態代理的實現方式,再看Spring中的源碼實現。
2.1.1 jdk動態代理
2.1.1.1 jdk動態代理的實現
jdk動態代理是代理一個接口,並由代理類實現InvocationHandler接口的方式實現
1、創建一個UserService接口類,並定義兩個方法
1 package com.spring.reading.proxy.jdk; 2 3 import com.spring.reading.vo.UserVo; 4 5 /** 6 * @author: cyhua 7 * @createTime: 2021/11/26 8 * @description: 9 */ 10 public interface UserService { 11 12 int add(UserVo userVo); 13 14 15 String update(UserVo userVo); 16 }
2、創建一個UserServiceImpl實現類,實現上面的接口
1 package com.spring.reading.proxy.jdk; 2 3 import com.spring.reading.vo.UserVo; 4 5 /** 6 * @author: cyhua 7 * @createTime: 2021/11/26 8 * @description: 9 */ 10 public class UserServiceImpl implements UserService { 11 @Override 12 public int add(UserVo userVo) { 13 System.out.println("add user sueccess" + userVo); 14 return 1; 15 } 16 17 @Override 18 public String update(UserVo userVo) { 19 return null; 20 } 21 }
3、創建一個代理類UserJdkProxy,實現InvocationHandler接口
1 package com.spring.reading.proxy.jdk; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 /** 7 * @author: cyhua 8 * @createTime: 2021/11/26 9 * @description: 10 */ 11 public class UserJdkProxy implements InvocationHandler { 12 13 /** 14 * 被代理的對象 15 */ 16 private Object object; 17 18 public UserJdkProxy(Object object) { 19 this.object = object; 20 } 21 22 @Override 23 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 24 System.out.println("方法之前執行:" + method.getName() + ";參數:" + args.toString()); 25 Object result = method.invoke(object, args); 26 System.out.println("方法之后執行" + method.getName() + ";結果" + result); 27 return result; 28 } 29 30 }
4、通過代理類生成代理對象並調用add接口
1 package com.spring.reading.proxy.jdk; 2 3 import com.spring.reading.vo.UserVo; 4 5 import java.lang.reflect.Proxy; 6 7 /** 8 * @author: cyhua 9 * @createTime: 2021/11/26 10 * @description: 11 */ 12 public class UserJdkProxyCaller { 13 14 public static void main(String[] args) { 15 UserVo userVo = new UserVo(); 16 Class[] interfaces = {UserService.class}; 17 UserService userService = (UserService) Proxy.newProxyInstance(UserJdkProxy.class.getClassLoader(), interfaces, new UserJdkProxy(new UserServiceImpl())); 18 int add = userService.add(userVo); 19 System.out.println("add:" + add); 20 } 21 }
上面第17行代碼中的userService對象是通過gdk動態代理創建的。
2.1.1.2 Spring中的應用
Spring中通過jdk實現的動態代理類的關系如下:
獲取代理對象的核心源代碼如下:
1 /** Config used to configure this proxy. */ 2 private final AdvisedSupport advised; 3 4 /** 5 * Is the {@link #equals} method defined on the proxied interfaces? 6 */ 7 private boolean equalsDefined; 8 9 /** 10 * Is the {@link #hashCode} method defined on the proxied interfaces? 11 */ 12 private boolean hashCodeDefined; 13 14 15 /** 16 * Construct a new JdkDynamicAopProxy for the given AOP configuration. 17 * 通過指定AOP配置類創建JdkDynamicAopProxy的構造方法 18 * @param config the AOP configuration as AdvisedSupport object 19 * @throws AopConfigException if the config is invalid. We try to throw an informative 20 * exception in this case, rather than let a mysterious failure happen later. 21 */ 22 public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException { 23 Assert.notNull(config, "AdvisedSupport must not be null"); 24 if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) { 25 throw new AopConfigException("No advisors and no TargetSource specified"); 26 } 27 this.advised = config; 28 } 29 30 31 @Override 32 public Object getProxy() { 33 return getProxy(ClassUtils.getDefaultClassLoader()); 34 } 35 36 /** 37 * 獲取指定類加載器的代理對象 38 * @param classLoader the class loader to create the proxy with 39 * (or {@code null} for the low-level proxy facility's default) 40 * @return 41 */ 42 @Override 43 public Object getProxy(@Nullable ClassLoader classLoader) { 44 if (logger.isTraceEnabled()) { 45 logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); 46 } 47 //通過advised獲取到被代理接口 48 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); 49 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); 50 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 51 }
上面代碼中第2行維護了一個被代理對象的配置類advised,該類的值通過22行的構造函數JdkDynamicAopProxy(AdvisedSupport config)傳入,在48行通過AopProxyUtil工具解析被代理的接口列表,很典型的的jdk動態代理實踐。
2.1.2 cglib動態代理
cglib動態代理代理的對象不是一個接口,而是一個具體的類,而且代理類需要實現MethodInterceptor接口
2.1.2.1 cglib動態代理的實現
1、引入axpectj的依賴
1 <dependency> 2 <groupId>org.springframework</groupId> 3 <artifactId>spring-aop</artifactId> 4 <version>5.2.9.RELEASE</version> 5 </dependency> 6 7 <dependency> 8 <groupId>org.aspectj</groupId> 9 <artifactId>aspectjweaver</artifactId> 10 <version>1.9.6</version> 11 </dependency>
2、創建一個類OrderService
1 package com.spring.reading.proxy.cglib; 2 3 import java.util.UUID; 4 5 /** 6 * @author: cyhua 7 * @createTime: 2021/11/27 8 * @description: 一個具體的類,提供訂單相關服務 9 */ 10 public class OrderService { 11 12 public String createOrder(Order order) { 13 System.out.println("OrderService createOrder begin..."); 14 String orderNumber = UUID.randomUUID().toString().replace("-", ""); 15 order.setOrderNumber(orderNumber); 16 System.out.println("OrderService createOrder end..."); 17 return orderNumber; 18 } 19 20 }
3、創建一個代理類CglibProxy
1 package com.spring.reading.proxy.cglib; 2 3 import org.springframework.cglib.proxy.Enhancer; 4 import org.springframework.cglib.proxy.MethodInterceptor; 5 import org.springframework.cglib.proxy.MethodProxy; 6 7 import java.lang.reflect.Method; 8 9 /** 10 * @author: cyhua 11 * @createTime: 2021/11/27 12 * @description: 實現MethodInterceptor,CGLIB動態代理 13 */ 14 public class CglibProxy<T> implements MethodInterceptor { 15 16 public T getProxy(Class<T> targetClass) { 17 Enhancer enhancer = new Enhancer(); 18 return (T) enhancer.create(targetClass, this); 19 } 20 21 @Override 22 public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { 23 System.out.println("OrderInterceptor intercept begin"); 24 return methodProxy.invokeSuper(o, args); 25 } 26 }
4、通過cglig代理生成UserService的對象,並調用createOrder方法
1 package com.spring.reading.proxy.cglib; 2 3 import java.math.BigDecimal; 4 import java.util.Arrays; 5 6 /** 7 * @author: cyhua 8 * @createTime: 2021/11/27 9 * @description: 10 */ 11 public class OrderServiceCaller { 12 13 public static void main(String[] args) { 14 Order order = new Order(); 15 order.setTotalPrice(new BigDecimal(200)); 16 order.setProductIds(Arrays.asList("1", "2", "3")); 17 OrderService orderService = new CglibProxy<OrderService>().getProxy(OrderService.class); 18 System.out.println("OrderServiceCaller end:orderNumber=" + orderService.createOrder(order)); 19 } 20 }
上面的第17行就是通過cglib動態代理生成UserService類對象的方式。
2.1.2.2 Spring中的實現
Spring中通過jdk實現的動態代理類的關系如下:
其中的CgligAopProxy就是實現cglib動態代理類,因為代碼較多,只選取核心代碼看看,具體實現大家直接看源碼:
1 // Configure CGLIB Enhancer... 2 //配置CGLIB的Enhancer 3 Enhancer enhancer = createEnhancer(); 4 if (classLoader != null) { 5 enhancer.setClassLoader(classLoader); 6 if (classLoader instanceof SmartClassLoader && 7 ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { 8 enhancer.setUseCache(false); 9 } 10 } 11 enhancer.setSuperclass(proxySuperClass); 12 enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); 13 enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); 14 enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader)); 15 16 //獲取回調接口:通過反射獲取 17 Callback[] callbacks = getCallbacks(rootClass); 18 Class<?>[] types = new Class<?>[callbacks.length]; 19 for (int x = 0; x < types.length; x++) { 20 types[x] = callbacks[x].getClass(); 21 } 22 // fixedInterceptorMap only populated at this point, after getCallbacks call above 23 //在上面的回調函數調用字后,執行過濾器,只使用已被填充的屬性 24 enhancer.setCallbackFilter(new ProxyCallbackFilter( 25 this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); 26 enhancer.setCallbackTypes(types); 27 28 // Generate the proxy class and create a proxy instance. 29 //生成代理類並創建一個代理對象 30 return createProxyClassAndInstance(enhancer, callbacks);
以上就是spring中代理模式的實現。
三、行為性模式
3.1 模板方法模式
模板方法模式傳送門:http://c.biancheng.net/view/1376.html
Spring中的應用:容器初始化過程
說明:AbstractApplicationContext,容器初始化的refresh方法就使用了經典模板方法模式
模板方法(Template Method)模式的定義如下:定義一個操作中的算法骨架,而將算法的一些步驟延遲到子類中,使得子類可以不改變該算法結構的情況下重定義該算法的某些特定步驟。它是一種類行為型模式。
Spring中的refres方法可以收是對模板方法模式的最佳實踐:
1 public void refresh() throws BeansException, IllegalStateException {
2 synchronized(this.startupShutdownMonitor) { 3 this.prepareRefresh(); 4 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); 5 this.prepareBeanFactory(beanFactory); 6 7 try { 8 this.postProcessBeanFactory(beanFactory); 9 this.invokeBeanFactoryPostProcessors(beanFactory); 10 this.registerBeanPostProcessors(beanFactory); 11 this.initMessageSource(); 12 this.initApplicationEventMulticaster(); 13 this.onRefresh(); 14 this.registerListeners(); 15 this.finishBeanFactoryInitialization(beanFactory); 16 this.finishRefresh(); 17 } catch (BeansException var9) { 18 if (this.logger.isWarnEnabled()) { 19 this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); 20 } 21 22 this.destroyBeans(); 23 this.cancelRefresh(var9); 24 throw var9; 25 } finally { 26 this.resetCommonCaches(); 27 } 28 29 } 30 }
refresh方法中定義了一套流程,其中postProcessBeanFactory、onRefresh以及一些其他方法中調用的方法,都是延遲到子類中實現,在AbstractApplicationContext類中只是定義了一個空實現,這就是模板方法模式中的鈎子方法,下面是對該模式中各個角色在Spring中的應用枚舉:
這個模式在Spring中的應用真的是太經典了,讓我直呼膜拜!!!
3.2 觀察者模式
觀察者模式傳送門:http://c.biancheng.net/view/1390.html
Spring中的應用:廣播上下文事件,由監聽器進行監聽處理
說明:觀察者(Observer)模式,指多個對象間存在一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。這種模式有時又稱作發布-訂閱模式、模型-視圖模式,它是對象行為型模式。在spring中,會有很多不同的事件和監聽器,來發布和監聽上下文的變化情況,並根據具體事件作出對應的處理
觀察者模式的主要角色如下。
- 抽象主題(Subject)角色:也叫抽象目標類,它提供了一個用於保存觀察者對象的聚集類和增加、刪除觀察者對象的方法,以及通知所有觀察者的抽象方法。
- 具體主題(Concrete Subject)角色:也叫具體目標類,它實現抽象目標中的通知方法,當具體主題的內部狀態發生改變時,通知所有注冊過的觀察者對象。
- 抽象觀察者(Observer)角色:它是一個抽象類或接口,它包含了一個更新自己的抽象方法,當接到具體主題的更改通知時被調用。
- 具體觀察者(Concrete Observer)角色:實現抽象觀察者中定義的抽象方法,以便在得到目標的更改通知時更新自身的狀態。
觀察者模式中的角色在Spring中的對應關系如下:
下面來看下各個角色的代碼實現:
1、抽象主題(Subject)角色,提供了一個用於保存觀察者對象的聚集類和增加、刪除觀察者對象的方法,以及通知所有觀察者的抽象方法。
1 /** 2 * Interface to be implemented by objects that can manage a number of 3 * {@link ApplicationListener} objects and publish events to them. 4 * 實現該接口的對象能夠管理多個ApplicationListener對象,並向它們發布事件 5 * 6 * <p>An {@link org.springframework.context.ApplicationEventPublisher}, typically 7 * a Spring {@link org.springframework.context.ApplicationContext}, can use an 8 * {@code ApplicationEventMulticaster} as a delegate for actually publishing events. 9 * 一個ApplicationEventPublisher,通常是一個spring ApplicationContext,能有使用ApplicationEventMulticaster作為實際發布事件的代理 10 * 該接口是觀察者模式中的抽象主題(Subject)角色: 11 * 也叫抽象目標類,提供了用戶保存觀察者對象的聚集類和增加、刪除觀察者對象的方法,以及通知所有觀察者的抽象方法 12 * 13 * 14 * @author Rod Johnson 15 * @author Juergen Hoeller 16 * @author Stephane Nicoll 17 * @see ApplicationListener 18 */ 19 public interface ApplicationEventMulticaster { 20 21 /** 22 * Add a listener to be notified of all events. 23 * 添加一個監聽器用來通知所有事件 24 * @param listener the listener to add 25 */ 26 void addApplicationListener(ApplicationListener<?> listener); 27 28 /** 29 * Add a listener bean to be notified of all events. 30 * 添加一個監聽器bean,用來通知所有事件 31 * @param listenerBeanName the name of the listener bean to add 32 */ 33 void addApplicationListenerBean(String listenerBeanName); 34 35 /** 36 * Remove a listener from the notification list. 37 * 從通知列表中移除一個監聽器 38 * @param listener the listener to remove 39 */ 40 void removeApplicationListener(ApplicationListener<?> listener); 41 42 /** 43 * Remove a listener bean from the notification list. 44 * 從通知列表中移除一個監聽器bean名稱 45 * @param listenerBeanName the name of the listener bean to remove 46 */ 47 void removeApplicationListenerBean(String listenerBeanName); 48 49 /** 50 * Remove all listeners registered with this multicaster. 51 * <p>After a remove call, the multicaster will perform no action 52 * on event notification until new listeners are registered. 53 * 移除這個多播器中所有的監聽器,移除之后,多播器將會在新的監聽器被注冊之前,被通知時都不會執行任何動作 54 */ 55 void removeAllListeners(); 56 57 /** 58 * Multicast the given application event to appropriate listeners. 59 * <p>Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)} 60 * if possible as it provides better support for generics-based events. 61 * 廣播給定的事給到合適的監聽器,如果可能的話,使用下面的方法,因為它提供了更好的支持 62 * @param event the event to multicast 63 */ 64 void multicastEvent(ApplicationEvent event); 65 66 /** 67 * Multicast the given application event to appropriate listeners. 68 * <p>If the {@code eventType} is {@code null}, a default type is built 69 * based on the {@code event} instance. 70 * @param event the event to multicast 71 * @param eventType the type of event (can be {@code null}) 72 * @since 4.2 73 */ 74 void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType); 75 76 }
2、具體主題(Concrete Subject)角色:也叫具體目標類,它實現抽象目標中的通知方法,當具體主題的內部狀態發生改變時,通知所有注冊過的觀察者對象。
具體主題有SimpleApplicationEventMulticaster和AbstractApplicationEventMulticaster,其中前者繼承自后者,SimpleApplicationEventMulticaster中實現了通知方法,源代碼如下:
1 @Override 2 public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { 3 //第一步:調用resolveDefaultEventType方法解析事件的類型,會返回類的全限定名 4 ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); 5 Executor executor = getTaskExecutor(); 6 for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { 7 if (executor != null) { 8 executor.execute(() -> invokeListener(listener, event)); 9 } 10 else if (this.applicationStartup != null) { 11 StartupStep invocationStep = this.applicationStartup.start("spring.event.invoke-listener"); 12 invokeListener(listener, event); 13 invocationStep.tag("event", event::toString); 14 if (eventType != null) { 15 invocationStep.tag("eventType", eventType::toString); 16 } 17 invocationStep.tag("listener", listener::toString); 18 invocationStep.end(); 19 } 20 else { 21 //將事件event通知給監聽器listener 22 invokeListener(listener, event); 23 } 24 } 25 }
3、抽象觀察者(Observer)角色:它是一個抽象類或接口,它包含了一個更新自己的抽象方法,當接到具體主題的更改通知時被調用。
抽象觀察者是ApplicationListener類,只有一個監聽接口onApplicationEvent,在監聽到event事件時做出相應的操作,源代碼如下:
1 package org.springframework.context; 2 3 import java.util.EventListener; 4 5 /** 6 * Interface to be implemented by application event listeners. 7 * 被應用程序監聽器實現的接口 8 * 9 * <p>Based on the standard {@code java.util.EventListener} interface 10 * for the Observer design pattern. 11 * 基於標准的EventListener接口實現的觀察者模式 12 * 13 * <p>As of Spring 3.0, an {@code ApplicationListener} can generically declare 14 * the event type that it is interested in. When registered with a Spring 15 * {@code ApplicationContext}, events will be filtered accordingly, with the 16 * listener getting invoked for matching event objects only. 17 * 從Spring 3.0開始,ApplicationListener能夠聲明它感興趣的事件類型,當一個ApplicationContext被注冊時, 18 * 事件將會被過濾,監聽器只會調用匹配的事件 19 * 該接口充當觀察者模式中的抽象觀察者(Observer): 20 * 它是一個抽象類或接口,包含了一個更新自己的抽象方法,當接到具體主題的更改通知(具體事件)時被調用 21 * 22 * 23 * @author Rod Johnson 24 * @author Juergen Hoeller 25 * @param <E> the specific {@code ApplicationEvent} subclass to listen to 26 * @see org.springframework.context.ApplicationEvent 27 * @see org.springframework.context.event.ApplicationEventMulticaster 28 * @see org.springframework.context.event.EventListener 29 */ 30 @FunctionalInterface 31 public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { 32 33 /** 34 * Handle an application event. 35 * @param event the event to respond to 36 */ 37 void onApplicationEvent(E event); 38 39 }
4、具體觀察者(Concrete Observer)角色:實現抽象觀察者中定義的抽象方法,以便在得到目標的更改通知時更新自身的狀態。
可以看到ApplicationListener有下面這些實現類
其中最常用的就是ContextRefreshListener,在應用上下文發生變化時進行處理,它其實是ApplicationListener的一個內部類,實現了ApplicationListener接口,源代碼如下:
1 /** 2 * ApplicationListener endpoint that receives events from this servlet's WebApplicationContext 3 * only, delegating to {@code onApplicationEvent} on the FrameworkServlet instance. 4 */ 5 private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> { 6 7 @Override 8 public void onApplicationEvent(ContextRefreshedEvent event) { 9 FrameworkServlet.this.onApplicationEvent(event); 10 } 11 }
在finishRefresh方法中,就調用了發布ContextRefreshListener事件的方法:
所以知道了這個設計模式在Spring中的應用,讀起源碼來就會更加的得心應手。
3.3 策略模式
策略模式傳送門:http://c.biancheng.net/view/1378.html
Spring中的應用:在實例化bean的過程中,會采用策略模式
策略(Strategy)模式的定義:該模式定義了一系列算法,並將每個算法封裝起來,使它們可以相互替換,且算法的變化不會影響使用算法的客戶。策略模式屬於對象行為模式,它通過對算法進行封裝,把使用算法的責任和算法的實現分割開來,並委派給不同的對象對這些算法進行管理。
策略模式的主要角色如下。
-
抽象策略(Strategy)類:定義了一個公共接口,各種不同的算法以不同的方式實現這個接口,環境角色使用這個接口調用不同的算法,一般使用接口或抽象類實現。
-
具體策略(Concrete Strategy)類:實現了抽象策略定義的接口,提供具體的算法實現。
-
環境(Context)類:持有一個策略類的引用,最終給客戶端調用。
在實例化一個對象時,是通過代理模式,還是構造方法,需要進行一定的決策,這里就用到了策略模式。策略模式中的角色在Spring中對應的類如下:
下面來看下Spring中各個角色的源代碼
1、抽象策略InstantiationStrategy
1 /** 2 * Interface responsible for creating instances corresponding to a root bean definition. 3 * 該接口的職責是:根據根bean的定義去創建一個實例 4 * <p>This is pulled out into a strategy as various approaches are possible, 5 * including using CGLIB to create subclasses on the fly to support Method Injection. 6 * 7 * @author Rod Johnson 8 * @author Juergen Hoeller 9 * @since 1.1 10 */ 11 public interface InstantiationStrategy { 12 13 /** 14 * Return an instance of the bean with the given name in this factory. 15 * 給工廠中的beanName對應的定義類返回一個實例 16 * @param bd the bean definition bean定義信息 17 * @param beanName the name of the bean when it is created in this context. 18 * The name can be {@code null} if we are autowiring a bean which doesn't 19 * belong to the factory. 20 * 在上下文中要創建的bean名稱,如果自動注入一個不屬於工廠的bean,該名稱就是空的 21 * @param owner the owning BeanFactory bean所屬的工廠 22 * @return a bean instance for this bean definition 返回該bean定義的實例 23 * @throws BeansException if the instantiation attempt failed 24 */ 25 Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) 26 throws BeansException; 27 28 /** 29 * Return an instance of the bean with the given name in this factory, 30 * creating it via the given constructor. 31 * 給工廠中的beanName對應的定義類返回一個實例,通過給定的構造器創建實例 32 * @param bd the bean definition 33 * @param beanName the name of the bean when it is created in this context. 34 * The name can be {@code null} if we are autowiring a bean which doesn't 35 * belong to the factory. 36 * @param owner the owning BeanFactory 37 * @param ctor the constructor to use 38 * @param args the constructor arguments to apply 39 * @return a bean instance for this bean definition 40 * @throws BeansException if the instantiation attempt failed 41 */ 42 Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, 43 Constructor<?> ctor, Object... args) throws BeansException; 44 45 /** 46 * Return an instance of the bean with the given name in this factory, 47 * creating it via the given factory method. 48 * 給工廠中的beanName對應的定義類返回一個實例,通過給定的工廠方法創建實例 49 * @param bd the bean definition 50 * @param beanName the name of the bean when it is created in this context. 51 * The name can be {@code null} if we are autowiring a bean which doesn't 52 * belong to the factory. 53 * @param owner the owning BeanFactory 54 * @param factoryBean the factory bean instance to call the factory method on, 55 * or {@code null} in case of a static factory method 56 * @param factoryMethod the factory method to use 57 * @param args the factory method arguments to apply 58 * @return a bean instance for this bean definition 59 * @throws BeansException if the instantiation attempt failed 60 */ 61 Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, 62 @Nullable Object factoryBean, Method factoryMethod, Object... args) 63 throws BeansException; 64 65 }
這個類中定義了三個方法,都是用來創建實例,只不過是三種不同的策略,它的具體實現類如下:
關系比較簡單,只有兩個實現類,且為繼承關系,下面來看在具體策略類中是怎么實現的
2、具體策略類SimpleInstantiationStrategy和CglibSubclassingInstantiationStrategy
先看SimpleInstantiationStrategy中的第一個方法(就看這一個方法吧~~)
1 @Override 2 public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { 3 // Don't override the class with CGLIB if no overrides. 4 if (!bd.hasMethodOverrides()) { 5 //如果某個bean中沒有重寫方法,則執行該邏輯 6 Constructor<?> constructorToUse; 7 synchronized (bd.constructorArgumentLock) { 8 constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; 9 if (constructorToUse == null) { 10 final Class<?> clazz = bd.getBeanClass(); 11 if (clazz.isInterface()) { 12 throw new BeanInstantiationException(clazz, "Specified class is an interface"); 13 } 14 try { 15 if (System.getSecurityManager() != null) { 16 constructorToUse = AccessController.doPrivileged( 17 (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor); 18 } 19 else { 20 constructorToUse = clazz.getDeclaredConstructor(); 21 } 22 bd.resolvedConstructorOrFactoryMethod = constructorToUse; 23 } 24 catch (Throwable ex) { 25 throw new BeanInstantiationException(clazz, "No default constructor found", ex); 26 } 27 } 28 } 29 //通過構造方法的方式實例化Bean 30 return BeanUtils.instantiateClass(constructorToUse); 31 } 32 else { 33 // Must generate CGLIB subclass. 34 //如果沒有重寫方法,則必須生成CGLIB的子類,通過cglib代理的方式實例化Bean 35 return instantiateWithMethodInjection(bd, beanName, owner); 36 } 37 }
它會判斷當前的Bean中是否有方法覆蓋,沒有覆蓋就通過構造器的方式進行實例化,否則通過CGLIB生成子類的實例,再進行實例化,因為bean是存在繼承關系的,在實例化一個子類之前,要先實例化其父類
其中的35行代碼調用了下面的方法:
1 /** 2 * Subclasses can override this method, which is implemented to throw 3 * UnsupportedOperationException, if they can instantiate an object with 4 * the Method Injection specified in the given RootBeanDefinition. 5 * Instantiation should use a no-arg constructor. 6 */ 7 protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { 8 throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy"); 9 }
該方法上的注釋說明:子類可以覆蓋這個方法過程中會拋出一個UnsupportedOperationException異常,如果它能用定義中給定的方法實例化一個對象,實例化必須使用無參構造方法。
下面來看在CglibSubclassingInstantiationStrategy中的實現,源代碼如下:
1 @Override 2 protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { 3 return instantiateWithMethodInjection(bd, beanName, owner, null); 4 } 5 6 @Override 7 protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, 8 @Nullable Constructor<?> ctor, Object... args) { 9 10 // Must generate CGLIB subclass... 11 return new CglibSubclassCreator(bd, owner).instantiate(ctor, args); 12 }
第3行調用第7行的方法,通過cglib代理,用構造函數進行實例化bean.
Spring容器在創建實例的過程中就調用了策略模式中的實例化方法,如下圖所示:
可以看到,這個地方又回到了refresh方法的流程當中來,這就是為什么我要把Spring中的策略模式作為閱讀源碼的前置知識點來介紹的原因,一切都是為了更好第地讀懂和理解源代碼。
說到這兒也差不多完了,其實這里的每一個設計模式都可以拎出來單獨寫一篇文章,因為我沒有介紹具體設計模式的實現方式,所以就寫在一篇文章中,這樣其實可以更好地理解設計模式,因為如果通過手寫舉例,無非是一些阿貓阿狗的簡單例子,並不會對設計模式有什么深刻的理解,結合Spring源碼,就會發現平時覺得一看就懂的設計模式,在Spring中需要經過一番研究才能搞清楚它們是怎么實現的。本文內容優點多,下面來做一個簡單的總結吧:
1、單例模式在獲取bean時使用,底層通過CurrentHashMap存儲beanName於bean實例的映射關系,是beanName級別的單例,而不是類級別的單例,這一點不同於真正意義上的單例模式
2、Spring中默認bean是單例模式,且是懶加載,即在容器啟動過程中完成創建;
3、原型模式,即多例模式,實現原型模式需要開發者自己配置,且默認懶加載,即在獲取時才會創建;
4、工廠模式是為了獲取Bean,有工廠方法模式和抽象工廠模式;
5、建造者模式用於構造復雜的bean,在http響應中使用,比如一個http響應體要包含header、body、status、cookie等,每個部分都是一個bean,此時構建響應體就可以用建造者模式;
6、觀察者模式,用來發布時間到監聽器,方便在應用上下文變化時做出及時的處理,在關鍵方法refresh源碼中有使用;
7、模板方法模式,在refresh方法中可以說是最佳實踐;
8、策略模式,因為容器管理的Bean可能是千奇百怪的,所以它需要各種創建實例的策略,這個策略就是通過策略模式實現的。
9、代理模式,理解jdk和cglib兩種動態代理,有助於理解AOP以及bean的實例化;
這是我看源碼過程中發現的策略模式,也許還有我沒有發現的,我會繼續發現.........
對不同設計模式的定義描述引自編程網,里面有很不錯的設計模式介紹:http://c.biancheng.net/view/1378.html,今天就這樣吧~~~睡了