spring最核心思想--ioc控制反轉
一核心概念
控制反轉:將bean的生成交給容器,程式可以從容器中獲取指定的bean。
個人理解:此優勢也是spring能夠流行併成為java主流框架的主要原因,java是幫助java程式設計師以物件的方式管理 記憶體,而spring則是一個管理物件的框架。如果使用spring,在開發中基本上不需要考慮記憶體相關的問題。
接下來從一個設計者的思路去交流下spring的設計思路
二需求
基於以上的需求,我們需要做的核心的需求的是:生成,管理bean,向使用者提供。
三設計
看到這,是不是第一反應就是可以用工廠模式,沒錯,spring框架中針對此設計也是工廠模式。核心類為Beanactory,核心方法為getBean()。
1 public interface BeanFactory { 2 /** 3 * 獲取bean 4 * @param name bean的名字 5 * @return bean 例項 6 * @throws Exception 7 */ 8 Object getBean(String name) throws Exception; 9 }
現在有個工廠,同時我們面對2個問題:
1BeanFactory如何知道生成什麼樣的bean(bean是由使用者指定的)?
2使用者如何定義一個bean,便於使用者使用也便於beanFactory?
接下來先考慮第二個問題,現在誰也不知道使用者將定義怎樣的bean,那就來個萬能大法,先定義的一個介面專門做這個事,介面為BeanDefinition。
回到第一個問題,我們如何將BeanDefinition告訴給BeanFactory?解決這個問題同時我們還要考慮可擴充套件性。這個解決方案是註冊模式。
public interface BeanDefinitionRegistry {
/**
* 註冊bean定義
* @param beanName bean名稱(bean的唯一標識)
* @param beanDefinition bean定義
* @throws BeanDefinitionRegistException 註冊異常
*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionRegistException;
}
每個bean通過BeanDefinitionRegistry介面通知給BeanFactory。
目前只剩下一個問題:BeanDefinition如何定義,通俗點就是BeanDefinition裡面都有什麼。
Bean生成都有哪些情況,
1是否單例
2bean類名
3生成方式:
3.1指定初始化方法
必須的資訊:bean的類名
3.2通過工廠模式
3.2.1靜態的
public class PersonFactory{
public static Person getPerson(){
return new Person();
}
}
3.2.2成員方法
public class PersonFactory{ public Person getPerson(){ return new Person(); } }
工廠模式下,必須獲取的資訊如下:工廠bean的命,工廠方法名
3.3new的方式
4銷燬的方法
具體介面如下:
public interface BeanDefinition { String SCOPE_SINGLETION = "singleton"; String SCOPE_PROTOTYPE = "prototype"; /** * 類 */ Class<?> getBeanClass(); /** * Scope */ String getScope(); /** * 是否單例 */ boolean isSingleton(); /** * 是否原型 */ boolean isPrototype(); /** * 工廠bean名 */ String getFactoryBeanName(); /** * 工廠方法名 */ String getFactoryMethodName(); /** * 初始化方法 */ String getInitMethodName(); /** * 銷燬方法 */ String getDestroyMethodName(); /** * 校驗bean定義的合法性 */ default boolean validate() { // 沒定義class,工廠bean或工廠方法沒指定,則不合法。 if (this.getBeanClass() == null) { if (StringUtils.isBlank(getFactoryBeanName()) || StringUtils.isBlank(getFactoryMethodName())) { return false; } } // 定義了類,又定義工廠bean,不合法 if (this.getBeanClass() != null && StringUtils.isNotBlank(getFactoryBeanName())) { return false; } return true; } }
ioc容器的主要設計均已設計完成。
簡單的實現原始碼如下:
package core.ioc.impl; import core.exception.BeanDefinitionRegistException; import core.ioc.BeanDefinition; import core.ioc.BeanDefinitionRegistry; import core.ioc.BeanFactory; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.xml.ws.WebServiceException; import java.io.Closeable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; public class DefaultBeanFactory implements BeanFactory, BeanDefinitionRegistry, Closeable { private final Log logger = LogFactory.getLog(DefaultBeanFactory.class); //存在beanDefinition的快取 private Map<String,BeanDefinition> beanDefinitionMap= new ConcurrentHashMap<>(256); //存放單例bean例項的快取 private Map<String,Object> beanMap = new ConcurrentHashMap<>(256); //獲取bean例項 public Object getBean(String name) throws Exception { return this.doGetBean(name); } protected Object doGetBean(String beanName) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { //驗證bean不能為空 Objects.requireNonNull(beanName,"beanName不能為空"); //檢視是否已經建立,如果已經建立則直接從快取中取得返回 Object instance = beanMap.get(beanName); if(null!=instance){ return instance; } //如果沒有建立,則需要建立, BeanDefinition bd = this.getBeanDefinition(beanName); Objects.requireNonNull(bd,"beanDefinition 不能為空"); Class<?> type=bd.getBeanClass(); if(type!=null){ if(StringUtils.isBlank(bd.getFactoryMethodName())){ //構造方法來構造物件 instance =this.createInstanceByConstructor(bd); }else{ //通過靜態工廠方法建立物件 instance=this.createInstanceByStaticFactoryMethod(bd); } }else{ //通過工廠bean方式來構造物件 instance=this.createInstanceByFactoryBean(bd); } //執行初始化方法,比如說給屬性賦值等 this.doInit(bd,instance); //如果是單例,則將bean例項放入快取中 if(bd.isSingleton()){ beanMap.put(beanName,instance); } return instance; } /** * 通過構造方法來構造物件 * @param bd dean定義 * @return bean例項 * @throws IllegalAccessException * @throws InstantiationException */ private Object createInstanceByConstructor(BeanDefinition bd) throws IllegalAccessException, InstantiationException { return bd.getBeanClass().newInstance(); } /** * 通過靜態工廠方法建立bean * @param bd bean定義 * @return bean 例項 * @throws NoSuchMethodException * @throws InvocationTargetException * @throws IllegalAccessException */ private Object createInstanceByStaticFactoryMethod(BeanDefinition bd) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Class<?> type=bd.getBeanClass(); Method m=type.getMethod(bd.getFactoryMethodName(),null); return m.invoke(type,null); } /** * 通過工廠bean 方式來構造物件 * @param bd * @return * @throws InvocationTargetException * @throws IllegalAccessException * @throws NoSuchMethodException */ private Object createInstanceByFactoryBean(BeanDefinition bd) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { Object factoryBean =this.doGetBean(bd.getFactoryBeanName()); Method m=factoryBean.getClass().getMethod(bd.getFactoryMethodName(),null); return m.invoke(factoryBean,null); } /** * 初始化 * @param bd * @param instance * @throws NoSuchMethodException * @throws InvocationTargetException * @throws IllegalAccessException */ private void doInit(BeanDefinition bd,Object instance) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { if(StringUtils.isNotBlank(bd.getInitMehtodName())){ Method m=instance.getClass().getMethod(bd.getInitMehtodName(),null); m.invoke(instance,null); } } @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionRegistException { Objects.requireNonNull(beanName,"註冊bean需要給入beanName"); Objects.requireNonNull(beanDefinition,"註冊bean需要給入beanDefinition"); //檢驗給如的bean是否合法 if(!beanDefinition.validata()){ throw new BeanDefinitionRegistException(String.format("名字為[%s]的bean的定義不合法:%s",beanName,beanDefinition)); } //驗證beanDefinition已經存在 if(this.containBeanDefinition(beanName)){ throw new BeanDefinitionRegistException(String.format("名字為[%s]的bean定義已經存在:%s", beanName,this.getBeanDefinition(beanName))); } this.beanDefinitionMap.put(beanName,beanDefinition); } /** * 獲取beanDefinition * @param beanName bean的名稱 唯一標識 * @return beanDefinition */ @Override public BeanDefinition getBeanDefinition(String beanName) { return this.beanDefinitionMap.get(beanName); } /** * 驗證beanDefinition是否已經存在 * @param beanName bean的名稱 唯一標識 * @return true:已存在 false:不存在 */ @Override public boolean containBeanDefinition(String beanName) { return this.beanDefinitionMap.containsKey(beanName); } /** * 執行指定的銷燬方法 * @throws WebServiceException */ @Override public void close() throws WebServiceException { //執行單例例項的銷燬方法 for(Map.Entry<String,BeanDefinition> e:this.beanDefinitionMap.entrySet()){ String beanName=e.getKey(); BeanDefinition bd=e.getValue(); if(bd.isSingleton() && StringUtils.isNotBlank(bd.getDestroyMethodName())){ Object instance = this.beanMap.get(beanName); try { Method m = instance.getClass().getMethod(bd.getDestroyMethodName()); m.invoke(instance,null); } catch (NoSuchMethodException e1) { logger.error(String.format("執行bean[%s] %s 的 銷燬方法異常!",beanName,bd), e1); e1.printStackTrace(); } catch (IllegalAccessException e1) { logger.error(String.format("執行bean[%s] %s 的 銷燬方法異常!",beanName,bd), e1); e1.printStackTrace(); } catch (InvocationTargetException e1) { logger.error(String.format("執行bean[%s] %s 的 銷燬方法異常!",beanName,bd), e1); e1.printStackTrace(); } } } } }DefaultBeanFactory
package core.ioc.impl; import core.ioc.BeanDefinition; import org.apache.commons.lang3.StringUtils; public class GenericBeanDefinition implements BeanDefinition { private Class<?> beanClass; //是否為單例 private String scope = BeanDefinition.SCOPE_SINGLETION; //bean工廠的名稱 private String factoryBeanName; //bean工廠方法名 private String factoryMethodName; //初始化方法 private String initMethodName; //銷燬方法 private String destroyMethodName; /** * 自動生成設定的方法 start */ public void setBeanClass(Class<?> beanClass) { this.beanClass = beanClass; } public void setScope(String scope) { if(StringUtils.isNoneBlank(scope)){ this.scope = scope; } } public void setFactoryBeanName(String factoryBeanName) { this.factoryBeanName = factoryBeanName; } public void setFactoryMethodName(String factoryMethodName) { this.factoryMethodName = factoryMethodName; } public void setInitMethodName(String initMethodName) { this.initMethodName = initMethodName; } public void setDestroyMethodName(String destroyMethodName) { this.destroyMethodName = destroyMethodName; } /** * 自動生成設定的方法 end */ @Override public Class<?> getBeanClass() { return this.beanClass; } @Override public String getScope() { return this.scope; } @Override public boolean isSingleton() { return BeanDefinition.SCOPE_SINGLETION.equals(this.scope); } @Override public boolean isPrototype() { return BeanDefinition.SCOPE_PROTOTYPE.equals(this.scope); } @Override public String getFactoryBeanName() { return this.factoryBeanName; } @Override public String getFactoryMethodName() { return this.factoryMethodName; } @Override public String getInitMehtodName() { return this.initMethodName; } @Override public String getDestroyMethodName() { return this.destroyMethodName; } @Override public String toString() { return String.format("GenericBeanDefinition [beanClass=%s, scope=%s, factoryBeanName=%s, " + "factoryMethodName=%s, initMethodName=%s, destroyMethodName=%s]", beanClass,scope,factoryBeanName,factoryMethodName,initMethodName,destroyMethodName); } /** * 疑問: 為什麼要重寫equals 方法 * * 重寫equals方法需要注意以下幾點: * 1自反性:對於任何非空引用x,x.equals(x)應該返回true * 2對稱:對於任何引用x,y,如果x.equals(y) 返回true,那麼 y.equals(x)也應該返回true。 * 3傳遞性:對於任何引用x,y和z,如果x=y 為true,那麼y=z也一定為true,x=z也一定為true。 * 4一致性:如果x和y引用的物件沒有發生變化,那麼返回呼叫x.equals(y),應該返回同樣的結果。 * 5非空性:對於任意非空引用x,x.equals(null)應該返回false。 * * 重寫equals方法,就必須重寫hashCode * 原因是HashMap的需要 */ @Override public boolean equals(Object obj) { if(this==obj){ return true; } if(null==obj){ return false; } if(getClass() !=obj.getClass()){ return false; } GenericBeanDefinition other=(GenericBeanDefinition) obj; //驗證每個屬性是否相當,只有當每個屬性均相等時,才是一個物件 if(beanClass ==null){ if(other.beanClass!=null){ return false; } }else if(!beanClass.equals(other.beanClass)){ return false; } if(destroyMethodName== null){ if(other.destroyMethodName!=null){ return false; } }else if(!destroyMethodName.equals(other.destroyMethodName) ){ return false; } if(factoryBeanName== null){ if(other.factoryBeanName!=null){ return false; } }else if(!factoryBeanName.equals(other.factoryBeanName) ){ return false; } if(factoryMethodName== null){ if(other.factoryMethodName!=null){ return false; } }else if(!factoryMethodName.equals(other.factoryMethodName) ){ return false; } if(initMethodName== null){ if(other.initMethodName!=null){ return false; } }else if(!initMethodName.equals(other.initMethodName) ){ return false; } if(scope== null){ if(other.scope!=null){ return false; } }else if(!scope.equals(other.scope) ){ return false; } return true; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((beanClass == null) ? 0 : beanClass.hashCode()); result = prime * result + ((destroyMethodName == null) ? 0 : destroyMethodName.hashCode()); result = prime * result + ((factoryBeanName == null) ? 0 : factoryBeanName.hashCode()); result = prime * result + ((factoryMethodName == null) ? 0 : factoryMethodName.hashCode()); result = prime * result + ((initMethodName == null) ? 0 : initMethodName.hashCode()); result = prime * result + ((scope == null) ? 0 : scope.hashCode()); return result; } }
&n