写自己的框架,让别人笑掉大牙吧(IOC2)
??? 上篇中主要使用配置文件来定义一些类实例之间的组织关系,这篇所要做的就是将其扩展,实现支持自定义化的注解,也就是使用注解来完成配置类实例之间的组织关系。废话不多,请看配置文件:
?
<?xml version="1.0" encoding="UTF-8"?><beans><bean id="test" single="true"/><autoScan package="com.sample.spring1.egclasses"/></beans>
?此配置文件说明了我们框架将会扫描的范围。
再看一下我们自定义的几个annotation
package com.sample.spring1.annotations;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;@Retention(RetentionPolicy.RUNTIME)public @interface AutoSet {public String id();}package com.sample.spring1.annotations;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME)public @interface Bean {public String id();}package com.sample.spring1.annotations;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;@Retention(RetentionPolicy.RUNTIME)public @interface Single {public boolean isSingle() default true; }?
再看看我们用来测试的几个类
EgDao
package com.sample.spring1.egclasses;import com.sample.spring1.annotations.Bean;import com.sample.spring1.annotations.Single; @Bean(id="egDao") @Single(isSingle=true)public class EgDao{public void callMe(){System.out.println("Dao is called");}}?
EgSevice
?
?
package com.sample.spring1.egclasses;import com.sample.spring1.annotations.AutoSet;import com.sample.spring1.annotations.Bean; @Bean(id="service")public class EgSevice{@AutoSet(id="egDao")private EgDao egDao;public void callMe(){egDao.callMe();}public EgDao getEgDao(){return egDao;}}?
EgService1
package com.sample.spring1.egclasses;import com.sample.spring1.annotations.AutoSet;import com.sample.spring1.annotations.Bean; @Bean(id="service1")public class EgSevice1{@AutoSet(id="egDao")private EgDao egDao;public void callMe(){egDao.callMe();}public EgDao getEgDao(){return egDao;}}ClassLoader 还试上文用到的并没有做什么特殊的处理
接下来就是我们框架的核心了
package com.sample.spring1;import java.io.File;import java.io.IOException;import java.lang.annotation.Annotation;import java.lang.reflect.Field;import java.net.URL;import java.util.Enumeration;import java.util.HashMap;import java.util.List;import java.util.Map;import org.jdom2.Document;import org.jdom2.Element;import org.jdom2.JDOMException;import org.jdom2.input.SAXBuilder;import com.sample.spring1.annotations.AutoSet;import com.sample.spring1.annotations.Single;public class SampleSpringContainer{private static final Map<String,Bean> beans=new HashMap<String, Bean>();static final Map<String,Object> singles=new HashMap<String, Object>();static{ SAXBuilder sb = new SAXBuilder(); try{Document doc =sb.build(SampleSpringContainer.class.getClassLoader().getResourceAsStream("com/sample/spring1/springSample.xml"));Element rootElement = doc.getRootElement();List<Element> beans = rootElement.getChildren("bean");buidXmlBeans(beans);List<Element> AnnotactionBeans = rootElement.getChildren("autoScan");if(!AnnotactionBeans.isEmpty()){buildAnnotationBeans(AnnotactionBeans);}initBeans();}catch (JDOMException e){e.printStackTrace();}catch (IOException e){e.printStackTrace();}}private static void buidXmlBeans(List<Element> beans){for(Element bean :beans){String id = bean.getAttributeValue("id");if(SampleSpringContainer.beans.containsKey(id))continue;String clas = bean.getAttributeValue("class");boolean single =Boolean.valueOf(bean.getAttributeValue("single"));Bean mbean=new Bean(clas, single);SampleSpringContainer.beans.put(id, mbean);List<Element> dependences = bean.getChildren("setProperty");for(Element dependence :dependences){String name = dependence.getAttributeValue("name");String agr = dependence.getAttributeValue("refer");Bean dbean2 = SampleSpringContainer.beans.get(agr);if(dbean2==null){buidDependenceBeans(beans,agr);dbean2=SampleSpringContainer.beans.get(agr);}if(dbean2==null){throw new IllegalArgumentException(id+"property "+name+"is not found");}mbean.getDependence().put(name, dbean2);}}}private static void buildAnnotationBeans(List<Element> annotactionBeans) throws IOException{for(Element el:annotactionBeans){String packgetName = el.getAttributeValue("package"); buildbyPackage(packgetName);}}private static void buildbyPackage(String packgetName) throws IOException{SampleClassLoader classLoader = SampleClassLoader.getClassLoader();String fileResource = packgetName.replace('.', '/');Enumeration<URL> resources = classLoader.getResources(fileResource);if(resources.hasMoreElements()){URL url=resources.nextElement();File file = new File(url.getFile());for(String f:file.list()){System.out.println(f);String[] split = f.split("\\.");if(split.length==1){//TODO load sub packagebuildbyPackage(packgetName+"."+f);continue;}if(split.length<2)continue;if(split[1].equals("class")){try{Class<?> loadClass = classLoader.loadClass(packgetName+"."+split[0]);Annotation[] classAnnotations = loadClass.getDeclaredAnnotations();com.sample.spring1.annotations.Single isSingle=null;com.sample.spring1.annotations.Bean beanAn=null;for(Annotation an:classAnnotations){if(an instanceof com.sample.spring1.annotations.Bean){beanAn= (com.sample.spring1.annotations.Bean) an;continue;}if(an instanceof Single){isSingle=(Single) an;}}if(beanAn!=null){buildBean(loadClass,beanAn,isSingle);}}catch (ClassNotFoundException e){e.printStackTrace();}}}}else{throw new IllegalArgumentException(packgetName+" can't be found!");}}private static void buildBean(Class<?> loadClass, com.sample.spring1.annotations.Bean beanAn,Single isSingle){Bean bean= new Bean(loadClass.getName(), isSingle==null?false:isSingle.isSingle());SampleSpringContainer.beans.put(beanAn.id(), bean);Field[] fiels = loadClass.getDeclaredFields();for(Field f:fiels){Annotation[] annotations = f.getAnnotations();AutoSet autoProperty=null;for(Annotation an:annotations){if(an instanceof AutoSet){autoProperty=(AutoSet) an;break;}}if(autoProperty!=null){Bean bean2 = SampleSpringContainer.beans.get(autoProperty.id());if(bean2==null){Class<? extends Field> class1 = f.getClass();Annotation[] classAnnotations = class1.getDeclaredAnnotations();com.sample.spring1.annotations.Single isSinglePro=null;com.sample.spring1.annotations.Bean beanAnPro=null;for(Annotation an:classAnnotations){if(an instanceof com.sample.spring1.annotations.Bean){beanAnPro= (com.sample.spring1.annotations.Bean) an;continue;}if(an instanceof Single){isSinglePro=(Single) an;}}if(beanAnPro!=null){buildBean(class1,beanAnPro,isSinglePro);}bean2 = SampleSpringContainer.beans.get(autoProperty.id());}bean.getDependence().put(f.getName(), bean2);}}}private static void initBeans(){for(Map.Entry<String, Bean> bean:beans.entrySet()){if(!bean.getValue().getDependence().isEmpty()){for(Map.Entry<String, Bean> dep:bean.getValue().getDependence().entrySet()){deepBuildDependence(dep.getValue().getDependence());}}singles.put(bean.getValue().getClassName(), bean.getValue().newInstance());}}private static void deepBuildDependence(Map<String, Bean> dependence){for(Map.Entry<String, Bean> dep:dependence.entrySet()){Bean bean = dep.getValue();if(!bean.getDependence().isEmpty()){deepBuildDependence(bean.getDependence());}singles.put(bean.getClassName(), bean.newInstance());}}private static void buidDependenceBeans(List<Element> beans,final String rid){for(Element bean :beans){String id = bean.getAttributeValue("id");if(!rid.equals(id))continue;String clas = bean.getAttributeValue("class");boolean single =Boolean.valueOf(bean.getAttributeValue("single"));Bean mbean=new Bean(clas, single);SampleSpringContainer.beans.put(id, mbean);List<Element> dependences = bean.getChildren("setProperty");for(Element dependence :dependences){String name = dependence.getAttributeValue("name");String agr = dependence.getAttributeValue("refer");Bean dbean2 = SampleSpringContainer.beans.get(agr);if(dbean2==null){buidDependenceBeans(beans,agr);dbean2=SampleSpringContainer.beans.get(agr);}if(dbean2==null){throw new IllegalArgumentException("");}mbean.getDependence().put(name, dbean2);}}}public static Object getBean(final String beanId){Bean bean = beans.get(beanId);if(bean!=null){if(bean.isSingle()){return singles.get(beanId);}else{return bean.newInstance();}}return null;}}class Bean{private String className;private boolean isSingle;public Bean(String className, boolean isSingle){super();this.className = className;this.isSingle = isSingle;}private Map<String,Bean> dependence=new HashMap<String, Bean>();public String getClassName(){return className;}public void setClassName(String className){this.className = className;}public boolean isSingle(){return isSingle;}public Map<String, Bean> getDependence(){return dependence;}public Object newInstance(){SampleClassLoader classLoader = SampleClassLoader.getClassLoader();Object newInstance=null;try{Class<?> loadClass = classLoader.loadClass(className);newInstance= loadClass.newInstance();for(Map.Entry<String, Bean> entity:dependence.entrySet()){Field field = loadClass.getDeclaredField(entity.getKey());field.setAccessible(true);if(entity.getValue().isSingle()){field.set(newInstance,SampleSpringContainer.singles.get(entity.getValue().getClassName()));}else{field.set(newInstance, entity.getValue().newInstance());}}}catch (ClassNotFoundException e){e.printStackTrace();}catch (InstantiationException e){e.printStackTrace();}catch (IllegalAccessException e){e.printStackTrace();}catch (SecurityException e){e.printStackTrace();}catch (NoSuchFieldException e){e.printStackTrace();}return newInstance;}}?
这个类是在上篇中的类在做了一些修改 实现了对annotation的支持
?
下面依旧,是个测试
package com.sample.spring1;import com.sample.spring1.egclasses.EgSevice;import com.sample.spring1.egclasses.EgSevice1;public class TestSpring{/** * @param args */public static void main(String[] args){EgSevice bean = (EgSevice) SampleSpringContainer.getBean("service");bean.callMe();EgSevice1 bean1 = (EgSevice1) SampleSpringContainer.getBean("service1");bean1.callMe();System.out.println(bean.getEgDao()==bean1.getEgDao());}}?
?