上篇中主要使用配置文件来定义一些类实例之间的组织关系,这篇所要做的就是将其扩展,实现支持自定义化的注解,也就是使用注解来完成配置类实例之间的组织关系。废话不多,请看配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="test" class="com.sample.spring1.egclasses.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 package
buildbyPackage(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());
}
}