终于到了激动人心的时刻了,首先感谢小伙伴们的阅读,如果能多点评论,多点探讨就更好了,没有交流让我觉得我写的东西只有标题有点价值,内容只是在浪费大家的时间。为了泪滴下周能写下一个框架orm,请小伙伴们能给点信心。前面3篇中介绍的大都是完成某一个层面的工具式的类,看起来就像是一盘散沙。原因就是缺少一个能够统管这盘散沙的头头,那么这篇内容将会以一个头头的角度告诉大家什么才叫化腐朽为神奇。

  我们先回想下spring框架中是否会出现如下类似的代码呢?

ApplicationContext context = new FileSystemXmlApplicationContext(filePath);

这个代码就是根据xml文件的路径获取了spring中的context对象,我习惯叫做上下文对象,根据这个对象我们就可以通过调用他的getBean方法根据id来获取到我们需要的实例对象了。下面我们也给我们的框架来一个类似的对象,当然之前我们仍然应该将接口实现类的模式进行到底。接口放在新建的包com.tear.ioc.context下面

package com.tear.ioc.context;

/**
* 这是ioc应用容器的接口
* @author rongdi
*
*/
public interface ApplicationContext {
/**
* 根据id找到bean对应的对象的实例
* @param id
* @return
*/
public Object getBeanInstance(String id);
/**
* IoC容器中是否包含id为参数的bean
* @param id
* @return
*/
public boolean beanIsExist(String id); /**
* 判断一个bean是否为单态
* @param name
* @return
*/
public boolean isSingleton(String id); /**
* 从容器中获得bean对应的实例, 如果从容器中找不到该bean, 返回null
* @param id
* @return
*/
public Object getBeanWithoutCreate(String id);
}

为了使用方便我们再给他一个抽象类的实现AbstractApplicationContext

package com.tear.ioc.context;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set; import org.dom4j.Document;
import org.dom4j.Element; import com.tear.ioc.bean.create.BeanCreator;
import com.tear.ioc.bean.create.BeanCreatorImpl;
import com.tear.ioc.bean.create.PropertyHandler;
import com.tear.ioc.bean.create.PropertyHandlerImpl;
import com.tear.ioc.bean.exception.BeanCreateException;
import com.tear.ioc.bean.xml.autowire.Autowire;
import com.tear.ioc.bean.xml.autowire.ByNameAutowire;
import com.tear.ioc.bean.xml.autowire.NoAutowire;
import com.tear.ioc.bean.xml.document.DocumentHolder;
import com.tear.ioc.bean.xml.document.XmlDocumentHolder;
import com.tear.ioc.bean.xml.element.CollectionElement;
import com.tear.ioc.bean.xml.element.LeafElement;
import com.tear.ioc.bean.xml.element.PropertyElement;
import com.tear.ioc.bean.xml.element.RefElement;
import com.tear.ioc.bean.xml.element.ValueElement;
import com.tear.ioc.bean.xml.element.loader.ElementLoader;
import com.tear.ioc.bean.xml.element.loader.ElementLoaderImpl;
import com.tear.ioc.bean.xml.element.parser.BeanElementParser;
import com.tear.ioc.bean.xml.element.parser.BeanElementParserImpl;
/**
* 该类继承ApplicationContext接口,定义成抽象类是因为本类中定义的方法还不够完善
* 不想本类被直接实例化来使用希望使用它扩展功能后的子类
* @author rongdi
*
*/
public abstract class AbstractApplicationContext implements ApplicationContext { /**
* 定义一个文档持有对象
*/
protected DocumentHolder documentHolder = new XmlDocumentHolder();
/**
* 定义一个元素加载对象
*/
protected ElementLoader elementLoader = new ElementLoaderImpl();
/**
* 定义一个Element元素读取类
*/
protected BeanElementParser elementParser = new BeanElementParserImpl();
/**
* 定义一个创建bean对象的类
*/
protected BeanCreator beanCreator = new BeanCreatorImpl();
/**
* 定义一个属性处理类
*/
protected PropertyHandler propertyHandler = new PropertyHandlerImpl();
/**
* 定义一个Map用来保存bean元素的id和生成的对应的实例,主要是单实例的bean的对象需要保存起来
*/
protected Map<String, Object> beanInstances = new HashMap<String, Object>(); /**
* 初始化Elements将对应的document元素中的Element调用elementLoader的方法缓存起来
* 可以读取多个xnl文件的路径,参数为一个字符串数组
* @param xmlPaths
*/
protected void initElements(String[] xmlPaths) {
try {
/**
* 获取当前项目的根路径
*/
URL classPathUrl = AbstractApplicationContext.class.getClassLoader().getResource(".");
/**
* 为防止路径出现汉字乱码的情况使用utf-8进行解码
*/
String classPath = java.net.URLDecoder.decode(classPathUrl.getPath(),"utf-8");
/**
* 遍历所有的路径
*/
for (String path : xmlPaths) {
/**
* 由根路径加传入的相对路径获取document元素
*/
Document doc = documentHolder.getDocument(classPath + path);
/**
* 将所有的路径对应的xml文件里的bean元素都缓存到elementLoader对象中
*/
elementLoader.addBeanElements(doc);
}
} catch (Exception e) {
e.printStackTrace();
} }
/**
* 创建一个bean实例, 如果找不到该bean对应的配置文件的Element对象, 抛出异常
* @param id
* @return
*/
protected Object createBeanInstance(String id) {
/**
* 首先直接在elementLoader对象中找id对应的元素
*/
Element e = elementLoader.getBeanElement(id);
/**
* 如果没找到抛出异常
*/
if (e == null)
throw new BeanCreateException("没找到 " + id+"对应的bean元素");
/**
* 调用本类定义的instance方法实例化该元素对应的类
*/
Object result = this.instanceBeanElement(e);
System.out.println("创建bean: " + id);
System.out.println("该bean的对象是: " + result);
/**
* 设值注入, 先判断是否自动装配
*/
Autowire autowire = elementParser.getAutowire(e);
if (autowire instanceof ByNameAutowire) {
/**
* 使用名称自动装配
*/
autowireByName(result);
} else if (autowire instanceof NoAutowire) {
/**
* 调用设置注入,给根据e元素生成的对象result设置e元素里配置的property属性值
*/
this.setterInject(result, e);
}
/**
* 返回创建的实例result
*/
return result;
}
/**
* 实例化一个bean, 如果该bean的配置有constructor-arg元素, 那么使用带参数的构造器
* @param e
* @return
*/
protected Object instanceBeanElement(Element e) {
/**
* 得到该bean元素的class属性的值
*/
String className = elementParser.getAttribute(e, "class");
/**
* 得到bean节点下面的constructor-arg元素
*/
List<Element> constructorElements = elementParser.getConstructorArgsElements(e);
/**
* 判断使用什么构造器进行创建(判断标准为bean元素下是否有constructor-arg子元素)
* 如果没有constructor-arg子元素调用无参构造器
*/
if (constructorElements.size() == 0) {
/**
* 没有constructor-arg子元素, 使用无参构造器
*/
return beanCreator.createBeanUseDefaultConstruct(className);
} else {
/**
* 有constructor-arg子元素,得到所有的构造参数 使用有参数构造器, 构造注入参数
*/
List<Object> args = getConstructArgs(e);
return beanCreator.createBeanUseDefineConstruct(className, args);
}
}
/**
* 创建所有的bean的实例, 延迟加载的不创建
*/
protected void createBeanInstances() {
/**
* 获取保存到elementLoader对象中的Bean元素
*/
Collection<Element> elements = elementLoader.getBeanElements();
/**
* 遍历所有的bean元素
*/
for (Element e : elements) {
/**
* 得到bean元素的lazy属性值
*/
boolean lazy = elementParser.isLazy(e);
/**
* 如果不是延迟加载
*/
if (!lazy) {
/**
* 得到该元素的id属性值
*/
String id = e.attributeValue("id");
/**
* 创建这个id所对应的bean的实例
*/
Object bean = this.getBeanInstance(id);
/**
* 如果bean实例进入处理bean的方法中
*/
if (bean == null) {
/**
* 处里bean的方法分是否是单例两种情况进行考虑
*/
handleBean(id);
}
}
}
} /**
* 处理bean, 如果是单态的, 则加到map中, 非单态, 则创建返回
* @param id
* @return
*/
protected Object handleBean(String id) {
/**
* 首先根据传入的id属性值找到该bean创建一个对应的bean的实例
*/
Object beanInstance = createBeanInstance(id);;
/**
* 如果是单例的则保存到Map中方便需要的时候取出
*/
if (isSingleton(id)) {
/**
* 单态的话, 放到map中
*/
this.beanInstances.put(id, beanInstance);
}
/**
* 返回创建的bean的实例
*/
return beanInstance ;
} /**
* 判断id值对应的bean是否为单态的
*/
public boolean isSingleton(String id) {
/**
* 使用ElementLoader方法获得对应的Element
*/
Element e = elementLoader.getBeanElement(id);
/**
* 使用ElementReader判断是否为单态
*/
return elementParser.isSingleton(e);
} /**
* 通过property元素为参数obj设置属性
* @param obj
* @param e
*/
protected void setterInject(Object obj, Element beanElement) {
/**
* 返回bean元素的所有的property标签对应的元素
*/
List<PropertyElement> properties = elementParser.getPropertyValue(beanElement);
/**
* 调用本类定义的方法得到所需要的属性名与所要设置的值的对信息
*/
Map<String, Object> propertiesMap = this.getPropertyArgs(properties);
/**
* 将对应的值设置到obj对象中
*/
propertyHandler.setProperties(obj, propertiesMap);
} /**
* 以map的形式得到需要注入的参数对象, key为setter方法对应的属性名, value为参数对象
* @param properties
* @return
*/
protected Map<String, Object> getPropertyArgs(List<PropertyElement> properties) {
/**
* 定义一个结果映射保存所需要的属性名与所要设置的值的对信息
*/
Map<String, Object> result = new HashMap<String, Object>();
/**
* 遍历所有的property元素
*/
for (PropertyElement p : properties) {
/**
* 得到prperty元素中的子元素
*/
LeafElement le = p.getLeafElement();
/**
* 判断如果是RefElement元素
*/
if (le instanceof RefElement) {
/**
* 将对应的属性名和需要设置进去的实例对象保存在map中
*/
result.put(p.getName(), this.getBeanInstance((String)le.getValue()));
} else if (le instanceof ValueElement) {
/**
* 如果是ValueElement,将对应的属性名和需要设置的值保存到Map中
*/
result.put(p.getName(), le.getValue());
} else if(le instanceof CollectionElement) {
/**
* 先判断是否是CollectionElement如果是再判断Collection标签里面放的是value标签还是ref标签
* 可以直接取出Collection里面的List判断还要判断类型是list还是set,根据不同情况调用不同的方法
* 将值放入result的map中
*/
if(this.childIsValueElement((CollectionElement)le)) {
if("list".equals(le.getType()))
result.put(p.getName(),this.arrayToArrayList((Object[])le.getValue()));
else {
result.put(p.getName(),this.arrayToHashSet((Object[])le.getValue()));
}
}
else {
if("list".equals(le.getType())){
result.put(p.getName(),this.arrayToArrayList(this.getValuesIfChildIsRefElement(le)));
}
else {
result.put(p.getName(),this.arrayToHashSet(this.getValuesIfChildIsRefElement(le)));
} }
}
}
/**
* 返回该结果信息
*/
return result;
}
/**
* 如果collectionElement下是ref元素那么调用该方法将集合标签中所有ref标签下对应的实例都生成好后
* 返回这些实例的一个Object数组形式
* @param le
* @return
*/
protected Object[] getValuesIfChildIsRefElement(LeafElement le) {
/**
* 定义一个临时存放的ArrayList
*/
List<Object> tempList = new ArrayList<Object>();
/**
* 遍历在CollectionElement里面取出的Object数组,因为这里都是ref标签,根据对应的值得到实例对象
*/
for(Object o:(Object[])le.getValue()) {
tempList.add(this.getBeanInstance((String)o));
}
return tempList.toArray();
} /**
* 将数组转换为ArrayList的方法
* @param obj
* @return
*/
protected List<Object> arrayToArrayList(Object[] obj) {
List<Object> temp = new ArrayList<Object>();
for(Object o:obj) {
temp.add(o);
}
return temp;
}
/**
* 将数组转换成HashSet的方法
*/
protected Set<Object> arrayToHashSet(Object[] obj) {
Set<Object> temp = new HashSet<Object>();
for(Object o:obj) {
temp.add(o);
}
return temp;
}
/**
* 判断CollectionElement中配置的是ValueElement元素,如果是则返回true
*/
protected boolean childIsValueElement(CollectionElement ce) {
/**
* 在CollectionElement元素中得到保存子元素的list判断该list中是否是ValueElement元素
* 如果是返回true
*/
if(ce.getList().get(0) instanceof ValueElement) {
return true;
}
return false;
}
/**
* 得到一个bean里面配置的构造参数
* @param e
* @return
*/
protected List<Object> getConstructArgs(Element beanElment) {
/**
* 得到该bean元素所有的构造参数元素,该参数可能使RefElement和ValueElement
*/
List<LeafElement> datas = elementParser.getConstructorValue(beanElment);
/**
* 定义一个结果信息保存得到的的参数集合
*/
List<Object> result = new ArrayList<Object>();
/**
* 遍历所有的构造参数元素
*/
for (LeafElement d : datas) {
/**
* 如果是ValueElement元素那么直接将该元素的值保存到结果中
*/
if (d instanceof ValueElement) {
d = (ValueElement)d;
result.add(d.getValue());
} else if (d instanceof RefElement) {
d = (RefElement)d;
String refId = (String)d.getValue();
/**
* 如果是引用元素, 则直接调getBean去获取(获取不到则创建),本方法本来就间接的被
* getgetBeanInstance方法调用了,现在在这个方法里在调用getBeanInstance
* 这个方法相当于形成了一个递归调用,递归的出口在引用所对一个的bean中再没有引用
*/
result.add(this.getBeanInstance(refId));
}
}
return result;
} /**
* 自动装配一个对象, 得到该bean的所有setter方法, 再从容器中查找对应的bean
* 例如, 如果bean中有一个setSchool(School)方法, 那么就去查名字为school的bean,
* 再调用setSchool方法设入对象中
* @param obj
*/
protected void autowireByName(Object obj) {
/**
* 得到该对象所有的setXXX方法和对应的属性(bean的id值)
*/
Map<String, Method> methods = propertyHandler.getSetterMethodsMap(obj);
/**
* 遍历所有的方法
*/
for (String s : methods.keySet()) {
/**
* 得到对应的bean元素
*/
Element e = elementLoader.getBeanElement(s);
/**
* 没有对应的元素配置, 继续循环
*/
if (e == null) continue;
/**
* 调用getBeanInstance方法返回beanInstance
*/
Object beanInstance = this.getBeanInstance(s);
/**
* 得到该对象的setter方法
*/
Method method = methods.get(s);
/**
* 将产生的实例调用executeMethod使用反射的方式设值到obj对象中,实现按名字的自动装配
*/
propertyHandler.executeMethod(obj, beanInstance, method);
System.out.println("执行"+method.getName()+"方法给对象:"+obj+"注入"+beanInstance);
}
}
/**
* 得到对应id的bean的实例
*/
public Object getBeanInstance(String id) {
Object beanInstance = this.beanInstances.get(id);
/**
* 如果获取不到该bean, 则调用handleBean处理
*/
if (beanInstance == null) {
/**
* 判断处理单态或者非单态的bean
*/
beanInstance = handleBean(id);
}
/**
* 返回得到的bean的实例
*/
return beanInstance;
}
/**
* 判断对应id的bean元素是否存在(直接到配置文件中找不要到elementLoader对象的缓存中找)
*/
public boolean beanIsExist(String id) {
/**
* 调用ElementLoader对象, 根据id得到对应的Element对象
*/
Element e = elementLoader.getBeanElement(id);
return (e == null) ? false : true;
} /**
* 在本类的缓存中获得id对应的实例,若果该id对应的bean是单态的就能获取到
*/
public Object getBeanWithoutCreate(String id) {
return this.beanInstances.get(id);
}
}

看到上面这个类是否有人会有点感觉了,没错这就是简单的使用了一下外观模式将之前看似无关的类全部加到这个外观类之中,降低了被加入类之间的耦合度,这就是为什么之前看起来那些类看起来没多大关系,就像各自层里面的工具类的原因。由于有了这个外观类的出现就像一个头头统筹了各类资源进行统一的调配。小伙伴们今后也可以多多用用这个模式,用起来也是很简单,呵呵。至于详细的注释我也是写的很辛苦了,全在代码里面了,多琢磨一下就不难理解了。

  到了这个层面了,应该做一下收尾了,可能有很多人会奇怪,我靠,你加了这么个抽象类,我到底要怎么使用才能达到spring的那种根据上下文context获取需要的bean的功能呢?别急,马上就来了。XmlApplicationContext类如下

package com.tear.ioc.context;

/**
* 这是真正使用的IoC的应用框架类,可以创建所有配置好的类的实例
* @author Administrator
*
*/
public class XmlApplicationContext extends AbstractApplicationContext { public XmlApplicationContext(String[] xmlPaths) {
/**
* 初始化文档和元素
*/
initElements(xmlPaths);
/**
* 创建所有bean的实例
*/
createBeanInstances();
}
}

  哈哈,看了上面的代码是不是很兴奋,Ioc终于完成了,而且只需要调用这个构造方法,将所有的xml文件以数组的形式传入进去就会自动创建所有非延迟加载的bean,而且也会完成依赖注入了。话不多说直接上测试代码就知道怎么用了。测试包test下建立com.tear.ioc.context包和com.tear.ioc.object包,object包下准备了各类的测试bean的类,具体泪有点多不贴出来了,可以直接到后面提供的百度云中去下载。测试用例如下

package com.tear.ioc.context;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import java.util.ArrayList;
import java.util.HashSet; import org.junit.After;
import org.junit.Before;
import org.junit.Test; import com.tear.ioc.object.XmlApplicationContextObject1;
import com.tear.ioc.object.XmlApplicationContextObject2;
import com.tear.ioc.object.XmlApplicationContextObject3;
import com.tear.ioc.object.XmlApplicationContextObject4; public class XmlApplicationContextTest {
ApplicationContext ctx; @Before
public void setUp() throws Exception {
ctx = new XmlApplicationContext(
new String[] { "/resources/context/XmlApplicationContext1.xml" });
} @After
public void tearDown() throws Exception {
ctx = null;
} @Test
public void testGetBean() { // 拿到第一个, 使用无参构造器创建
XmlApplicationContextObject1 obj1 = (XmlApplicationContextObject1) ctx
.getBeanInstance("test1");
assertNotNull(obj1);
} @Test
public void testSingleton() {
// test1是单态bean
XmlApplicationContextObject1 obj1 = (XmlApplicationContextObject1) ctx
.getBeanInstance("test1");
XmlApplicationContextObject1 obj2 = (XmlApplicationContextObject1) ctx
.getBeanInstance("test1");
assertEquals(obj1, obj2);
// test3不是单态bean
XmlApplicationContextObject1 obj3 = (XmlApplicationContextObject1) ctx
.getBeanInstance("test3");
XmlApplicationContextObject1 obj4 = (XmlApplicationContextObject1) ctx
.getBeanInstance("test3");
assertFalse(obj3.equals(obj4));
} @Test
public void testConstructInjection() {
XmlApplicationContextObject1 obj1 = (XmlApplicationContextObject1) ctx
.getBeanInstance("test1");
// 拿到第二个, 使用多参数构造器创建
XmlApplicationContextObject2 obj2 = (XmlApplicationContextObject2) ctx
.getBeanInstance("test2");
assertNotNull(obj2);
assertEquals(obj2.getName(), "rongdi");
assertEquals(obj2.getAge(), 22);
assertEquals(obj2.getObject1(), obj1);
} /*
* 测试自动装配
*/
@Test
public void testAutowire() { XmlApplicationContextObject3 obj1 = (XmlApplicationContextObject3) ctx
.getBeanInstance("test4");
assertNotNull(obj1);
XmlApplicationContextObject1 obj2 = obj1.getObject1();
System.out.println(obj2);
assertNotNull(obj2);
XmlApplicationContextObject1 obj3 = (XmlApplicationContextObject1) ctx
.getBeanInstance("object1");
assertEquals(obj2, obj3);
} /*
* 测试是否包含该bean
*/
@Test
public void testContainsBean() {
boolean result = ctx.beanIsExist("test1");
assertTrue(result);
result = ctx.beanIsExist("test5");
assertTrue(result);
result = ctx.beanIsExist("No exists");
assertFalse(result);
} /*
* 测试延迟加载
*/
@Test
public void testLazyInit() {
// test5是延迟加载的, 没有调用过getBean方法, 那么容器中就不会创建这个bean
Object obj = ctx.getBeanWithoutCreate("test5");
assertNull(obj);
// System.out.println(obj);
obj = ctx.getBeanInstance("test5");
assertNotNull(obj);
System.out.println(obj);
} /*
* 测试设值注入
*/
@Test
public void testSetProperties() {
XmlApplicationContextObject3 obj1 = (XmlApplicationContextObject3) ctx
.getBeanInstance("test6");
XmlApplicationContextObject1 obj2 = (XmlApplicationContextObject1) ctx
.getBeanInstance("object1");
assertEquals(obj1.getName(), "rongdi");
assertEquals(obj1.getAge(), 22);
assertEquals(obj1.getObject1(), obj2);
XmlApplicationContextObject4 obj4 = (XmlApplicationContextObject4) ctx
.getBeanInstance("test7");
System.out.println((ArrayList<Object>) obj4.getList());
System.out.println((HashSet<Object>) obj4.getSet());
System.out.println((ArrayList<Object>) obj4.getRefTest());
} }

从上面测试用例的方法中我们就可以看到我们的Ioc框架的完整使用方法了。相信小伙伴小心琢磨下,人人都能写出自己的Ioc了,当然该Ioc框架功能还不是很完善,,比如spring的Ioc中可以按照类型注入和名称注入,我们只实现了按名称注入,小伙伴们需要自己实现一个AutoWire接口改一下代码不难实现。至于最近一直都很流行的注解配置的方式,我给小伙伴们提一个自己的实现思路,相信大多数人都能实现。注解方式和xml配置方式的区别之处只在于loader层和parser层,我们可以仿照目前的流程写一个注解的loader层和一个注解的parser层然后在我们AbstractApplicationContext类中再集成进入这两个类,然后改下AbstractApplicationContext中的方法就能实现,这也算是外观模式的一个好处了。如果说小伙伴们的呼声比较高,我会考虑在这周抽时间写下注解的实现部分,不然我就认为大家都能自己完成。就会考虑去写下一个框架orm了。再次重申,泪滴分享的项目并非是要取代现存的已经经过时间检验过的完善的框架,只为了让大家更加深入的理解和使用现有的项目,所以代码在性能方面没有花时间作过多的考虑。

  好了,一如既往的屌丝专用百度云源码地址http://pan.baidu.com/s/1bn70g2N

自己动手编写IOC框架(四)的更多相关文章

  1. 自己动手编写IOC框架(一)

    博客创建了2年多了,一直没敢写点东西,怕技术不够误导了别人.2年多后的今天我已经很有信心能够为需要帮助的人做点微薄的贡献了.这是我第一次写博客,先自我介绍一下.本人网名泪滴,一个非常伤心的名字,生活中 ...

  2. 自己动手编写IOC框架(三)

    刚写博客浏览量第一天就有1000多人次,给了我很大的鼓舞决定熬夜再写一篇.对于前两篇来说无非就是使用dtd验证xml,然后解析xml,和IOC的核心还是差的很远,相信很多小伙伴们都感觉看得不过瘾了,这 ...

  3. 自己动手编写IOC框架(二)

    万事开头难,上篇已经起了一个头,之后的事情相对就简单了.上次定义了框架所需的dtd也就是规定了xml中该怎么写,有哪些元素.并且我们也让dtd和xml绑定在了一起,使dtd对xml的格式进行校验,并且 ...

  4. 自己动手写Spring框架--IOC、MVC

    对于一名Java开发人员,我相信没有人不知道 Spring 框架,而且也能够轻松就说出 Spring 的特性-- IOC.MVC.AOP.ORM(batis). 下面我想简单介绍一下我写的轻量级的 S ...

  5. 自己动手编写spring IOC源码

    前言:对于spring IOC概念不是很了解的朋友可以阅读我上一篇博客--轻松理解spring IOC(这两篇博客也是由于我的个人原因导致现在才发布,惭愧啊).通过这篇博客的理解之后,相信大家会对sp ...

  6. 国人编写的开源 .net Ioc 框架——My.Ioc 简介

    My.Ioc 是作者开发的一款开源 IoC/DI 框架,下载地址在此处.它具有下面一些特点: 高效 在实现手段上,My.Ioc 通过使用泛型.缓存.动态生成代码.延迟注册.尽量使用抽象类而非接口等方式 ...

  7. 组件化框架设计之AOP&IOC(四)

    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 本篇文章将从以下两个方面来介绍组件化框架设计: [AOP(面向切 ...

  8. OWIN系列之自己动手编写中间件

    一.前言 1.基于OWIN的项目摆脱System.Web束缚脱颖而出,轻量级+跨平台,使得ASP.NET应用程序只需依赖这个抽象接口,不用关心所运行的Web服务器. 2.OWIN.dll介绍 使用反编 ...

  9. IOC框架之Ninject 简介

    还是那几句话: 学无止境,精益求精 十年河东,十年河西,莫欺少年穷 学历代表你的过去,能力代表你的现在,学习代表你的将来 上篇博客介绍了依赖注入的三种方式:构造方法注入,属性注入,接口注入!详情请参考 ...

随机推荐

  1. 使用ftp软件上传下载php文件时换行丢失bug(全部变为一行)

    文章来源:http://www.piaoyi.org/computer/ftp-php-r-n-bug.html 正 文: 在使用ftp软件上传下载php源文件时,我们偶尔会发现在本地windows下 ...

  2. LeetCode 229. Majority Element II (众数之二)

    Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. The algorit ...

  3. 浅析Entity Framework Core中的并发处理

    前言 Entity Framework Core 2.0更新也已经有一段时间了,园子里也有不少的文章.. 本文主要是浅析一下Entity Framework Core的并发处理方式. 1.常见的并发处 ...

  4. 最新数据库排行,Oracle略显疲惫

    9月份TOPDB Top Database Index排行榜出炉,TOPDB Top Database Index是根据数据库在谷歌上的搜索频率分析得出的,数据库被搜索的频率越大,表示数 9月份的TO ...

  5. 安装mayavi和VTK库的血泪史

    一开始安装VTK库是从官网上下载,但是怎么都找不到whl文件,只有exe文件(vtkpython-7.1.1-Windows-64bit.exe).下载安装之后再PyCharm中import vtk出 ...

  6. 2-SAT问题总结

    2-SAT问题总结 2-SAT问题:n个布尔型的变量,给出m个约束条件,约束条件例如:A,B不能同时为真,A,B必须同时为真等. 看了算法入门经典中的解决办法,关于这种解决办法比较容易理解,并且效率也 ...

  7. hdu 3555 Bomb(不要49,数位DP)

    Bomb Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submi ...

  8. 通过xinetd服务管理 rsync 实现开机自启动

    1.1 xinetd服务配置 1.1.1 检查xinetd服务是否安装 [root@backup ~]# rpm -qa xinetd [root@backup ~]# rpm -ql xinetd ...

  9. 分析Array.apply(null, { length: 5 })

    Array.apply(null, { length: 5 }) 和 Array(5)有什么不同 注意:ES5,apply函数的第二个参数除了可以是数组外,还可以是类数组对象 // 类转成真正的数组 ...

  10. 手机网站的tips[转载]

    原文:http://www.haorooms.com/post/phone_web 1. 安卓浏览器看背景图片,有些设备会模糊. 用同等比例的图片在PC机上很清楚,但是手机上很模糊,原因是什么呢? 经 ...