控制反轉:將bean的生成交給容器,程序能夠從容器中獲取指定的bean。java
我的理解:此優點也是spring可以流行併成爲java主流框架的主要緣由,java是幫助java程序員以對象的方式管理 內存,而spring則是一個管理對象的框架。若是使用spring,在開發中基本上不須要考慮內存相關的問題。程序員
接下來從一個設計者的思路去交流下spring的設計思路spring
基於以上的需求,咱們須要作的核心的需求的是:生成,管理bean,向使用者提供。apache
看到這,是否是第一反應就是能夠用工廠模式,沒錯,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是由用戶指定的)?ide
2用戶如何定義一個bean,便於用戶使用也便於beanFactory?ui
接下來先考慮第二個問題,如今誰也不知道用戶將定義怎樣的bean,那就來個萬能大法,先定義的一個接口專門作這個事,接口爲BeanDefinition。this
回到第一個問題,咱們如何將BeanDefinition告訴給BeanFactory?解決這個問題同時咱們還要考慮可擴展性。這個解決方案是註冊模式。spa
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(); } } } } }
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; } }