容器介面

28之家發表於2016-05-15

  我們要完成自動裝配,那麼就要有一個存放bean物件的容器,然後要有裝配的註解,那麼哪些類該被存到容器呢,在spring中我們使用過@Service、@Resource等,看下面的程式碼,你也可以做到。

    來看看這是一個簡單的容器介面

/**
 * 容器介面
 * @author:rex
 * @create_time:2014-6-26
 * @version:V1.0
 */
public interface Container {

	Object getBean(String name, BeanType beanType);
	
	Object getBean(Class<?> type, BeanType beanType);
	
	Set<?> getBeanNames();
	
	Collection<?> getBeans();
	
	boolean hasBean(Class<?> clazz);
	
	boolean hasBean(String name);
	
	void registBean(Class<?> clazz);

	void initWired();
	
}

    這個容器提供了基礎的存取方法,分別是獲取bean物件和註冊、是否包含bean,還有一個初始化的方法。

    接下來我們來為容器做一個基本的實現。    

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import com.biezhi.ioc.BeanType;
import com.biezhi.ioc.Container;
import com.biezhi.ioc.anntation.Autowired;

/**
 * 預設的bean容器實現
 * @author:rex
 * @create_time:2014-6-26
 * @version:V1.0
 */
public class DefaultContainerImpl implements Container {

	//存放bean的容器
	private final Map<StringObject> beansMap = new HashMap<StringObject>();
	
	public DefaultContainerImpl() {
		//初始化載入bean
		ContainerLoader c = new ContainerLoader(this);
		c.init();
	}
	
	@Override
	public Object getBean(String name, BeanType beanType) {
		try {
			if(beanType == BeanType.NEW)
				return Class.forName(name).newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return beansMap.get(name);
	}
	
	@Override
	public Object getBean(Class<?> type, BeanType beanType) {
		try {
			if(beanType == BeanType.NEW)
				return type.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		Iterator<Object> it = this.beansMap.values().iterator();
		while(it.hasNext()){
			Object obj = it.next();
			if(type.isAssignableFrom(obj.getClass())){
				return obj;
			}
		}
		return null;
	}

	@Override
	public Set<?> getBeanNames(){
		return beansMap.keySet();
	}
	
	@Override
	public Collection<?> getBeans(){
		return beansMap.values();
	}

	@Override
	public boolean hasBean(Class<?> clz) {
		if(null != this.getBean(clz, null)){
			return true;
		}
		return false;
	}
	
	@Override
	public boolean hasBean(String name){
		if(null != this.getBean(name, null)){
			return true;
		}
		return false;
	}

	/**
	 * 註冊一個bean物件到容器裡
	 */
	@Override
	public void registBean(Class<?> clazz){
		String name = clazz.getCanonicalName();
		try {
			if(!Modifier.isAbstract(clazz.getModifiers()) && 
			    !Modifier.isInterface(clazz.getModifiers())){
				Object obj = clazz.newInstance();
				beansMap.put(name, obj);
			}
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} 
	}
	
	/**
	 * 初始化注入
	 */
	@Override
	public void initWired(){
		Iterator<Object> it = this.beansMap.values().iterator();
		try {
			while(it.hasNext()){
				Object obj = it.next();
				Field[] fields = obj.getClass().getDeclaredFields();
				for(Field field : fields){
					Autowired autowired = 
					    field.getAnnotation(Autowired.class);
					if(null != autowired){
						//要注入的欄位
						Object wiredField = 
						    this.getBean(field.getType(), null);
						if(null == wiredField){
    						       throw new RuntimeException("Unable to load "+field.getType().getCanonicalName()+"!");
						}
						boolean accessible = field.isAccessible();
						field.setAccessible(true);
						field.set(obj, wiredField);
						field.setAccessible(accessible);
					}
				}
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} 
	}
}

    在構造器裡將掃描到的類載入到容器裡,然後提供註冊bean和獲取bean的方法。

import java.io.File;
import java.io.FileFilter;
import java.util.HashSet;
import java.util.Set;

import com.biezhi.ioc.Container;
import com.biezhi.ioc.anntation.Service;
import com.biezhi.ioc.util.ClassHelper;

/**
 * 載入容器bean
 * @author:rex
 * @create_time:2014-6-26
 * @version:V1.0
 */
public class ContainerLoader {
	
	private Container container;
	
	public ContainerLoader(Container container) {
		this.container = container;
	}
	
	public void init(){
		//載入要掃描的包,這裡可以使用配置檔案,我們就預設掃描所有類
		Set<String> packages = getPackages();
		for(String pack : packages){
			scanPack(pack);
		}
		//初始化注入
		container.initWired();
	}
	
	private void scanPack(String pack){
		Set<Class<?>> classes = ClassHelper.scanPackage(pack);
		for(Class<?> clazz : classes){
			// 這裡我只把帶有@Service註解的存進去了,你也可以存其他的或者全部
			Service service = clazz.getAnnotation(Service.class);
			if(null != service){
				//將掃描到的物件儲存到容器中
				container.registBean(clazz);
			}
		}
	}
	
	/**
	 * 獲取當前classes的包名稱
	 * @author:rex  
	 * @return
	 */
	private Set<String> getPackages(){
		Set<String> packages = new HashSet<String>();
		String appPath = ContainerLoader.class.getResource("/").getPath();
		File classDir = new File(appPath);
		// 如果存在 就獲取包下的所有檔案 包括目錄
		File[] dirfiles = classDir.listFiles(new FileFilter() {
			public boolean accept(File file) {
				return file.isDirectory();
			}
		});
		for(File f : dirfiles){
			packages.add(f.getName());
		}
		return packages;
	}
}

    這個類是載入需要的類檔案。還有幾個程式碼檔案沒有貼出來,想看程式碼的等會打包自己看。

    接下來我們看看這個測試,

    

@Service
public class A {

	String name = "菊花";
	
	public void say(){
		System.out.println("hello, I,m rex !");
	}
}

@Service
public class B {

	@Autowired
	private A a;
	
	private String qq = "3838438";
	
	public void hehe(){
		a.say();
		System.out.println("請問您是" + a.name + "嗎?");
	}
	
	public String getQq(){
		return this.qq;
	}
}

public class Test {

	public static void main(String[] args) {
		Container c = new DefaultContainerImpl();
		c.initWired();
		//System.out.println(c.getBeanNames());
		B b = (Bc.getBean(B.classBeanType.SINGLE);
		b.hehe();
		System.out.println(b.getQq());
		System.out.println("==================");
		B b2 = (Bc.getBean(B.classBeanType.NEW);
		b2.hehe();
	}
}

    執行結果:

hello, I,m rex !
請問您是菊花嗎?
3838438
==================
Exception in thread "main" java.lang.NullPointerException
	at com.biezhi.ioc.test.B.hehe(B.java:15)
	at com.biezhi.ioc.test.Test.main(Test.java:18)

好了,這樣就基本完成了一個簡單的ioc自動裝配。有喜歡的朋友可以參考程式碼。點選下載


快樂賺 http://www.wanzhuanlewangba.com/

www.baiyi1.cn

聚享遊 http://www.tiantanzuan.com/站內文章,如需轉載,請保留作者和出處(雲棲社群),並郵件通知雲棲社群(yqeditor@list.alibaba-inc.com)。


相關文章