spring最核心思想--ioc控制反转
2020-03-30 16:06:19来源:博客园 阅读 ()
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; } }
原文链接:https://www.cnblogs.com/jjdyzz/p/12563342.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:五分钟学后端技术:如何学习Java工程师必须要会的RPC
下一篇:Base64
- Spring系列.ApplicationContext接口 2020-06-11
- springboot2配置JavaMelody与springMVC配置JavaMelody 2020-06-11
- 给你一份超详细 Spring Boot 知识清单 2020-06-11
- SpringBoot 2.3 整合最新版 ShardingJdbc + Druid + MyBatis 2020-06-11
- 掌握SpringBoot-2.3的容器探针:实战篇 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash