天天看點

模仿Spring架構進行方法的注入

模仿Spring架構進行方法的注入

上一篇文章之中,我們對于成員進行了注入,自動生成了bean

這次我們考慮一下 特殊情況 有的成員 (也就是要注入的類)可能是jar包裡面的類,如果想要進行注入應該怎麼辦呢?

我們想到利用方法進行傳入 并且對方法進行注解

@Retention(RUNTIME)
@Target(METHOD)
public @interface Bean {
	String name() default "";
}
/*@Bean是放在方法的注釋,它會告訴Spring這個方法會傳回一個對象,
 * 該對象要注冊為Spring應用上下文中的bean。換句話說,
 * 它很明确地告訴被注釋的方法,你給我産生一個Bean,
/
再來看看 被注解的類
@Component
public class Configuration {
	public Configuration() {
	}
	@Bean
	public Point getPoint(Complex complex) {
		Point point = new Point(complex);
		return point;
	}
//	假設 Complex  是jar包裡面的 一個類 ,不能進行注解
//	利用 這個類  
//	構造方法裡面  進行 單參構造 傳入 Complex 類到Point類裡面
//  想要實作注入
}

           

我們的做法是先将普通的Component注解類 放到beanpool裡去

包掃描包掃描的部落格(附源碼):

public void scanBeanByPackage(String packageName) {
		OnReadyBeanMethodDefinition orbmd = new OnReadyBeanMethodDefinition();
		ParameterDependance parameterDependance = new ParameterDependance();
		
		new PackageScanner() {
			@Override
			public void dealClass(Class<?> klass) {
				if (klass.isPrimitive()
						|| klass.isInterface()
						|| klass.isAnnotation()
						|| klass.isEnum()
						|| klass.isArray()
						|| !klass.isAnnotationPresent(Component.class)) {
					return;
				}
				
				Object object = null;
				try {
					object = klass.newInstance();
					BeanDefinition bd = new BeanDefinition();
					bd.setKlass(klass);
					bd.setObject(object);
					
					beanPool.put(klass.getName(), bd);
				} catch (InstantiationException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
				
				// 查找并處理Bean注解的方法
				// 現在隻能将所有Bean注解的方法收集起來
				collectBeanMethod(klass, object, orbmd);
			}
		}.packageScanner(packageName);
		
		// 現在開始處理Bean注解的方法
		parameterDependance.checkOnReady(orbmd);
		processBeanMethod(parameterDependance, orbmd);
	}
	

           

将所有的方法進行收集,

其中

方法裡面有無參,單參,多參 并且同樣一個方法的參數類型也可能一樣

由于 可能方法參數之間存在着依賴關系:

(一個方法的成功傳回結果有可能使得另一個函數的參數得到滿足)

是以我們想到了利用 方法的參數類型為 作為key 将所有需要參數的方法組成一個list作為值,作為 值,建立一個 Map

如圖:

模仿Spring架構進行方法的注入

(1)建立一個 ParameterDependance類

private static final Map<Class<?>, List<BeanMethodDefinition>> parameterDependance;
	static {
		parameterDependance = new HashMap<Class<?>, List<BeanMethodDefinition>>();
	}

添加依賴關系
boolean addDependance(BeanMethodDefinition methodDefinition) {
		Method method = methodDefinition.getMethod();
		int parameterCount = method.getParameterCount();
//		如果參數為0 或者小于0 那麼就無須考慮依賴關系
		if (parameterCount <= 0) {
			return false;
		}
		
		Parameter[] parameters = method.getParameters();
		for (Parameter parameter : parameters) {
			Class<?> type = parameter.getType();
			if (!parameterDependance.containsKey(type)) {
//				用參數類型作為鍵,若多個函數包含同一類型的參數
//				則将這幾個函數形成List
				parameterDependance.put(type, new ArrayList<BeanMethodDefinition>());
			}
			List<BeanMethodDefinition> bmdList = parameterDependance.get(type);
			bmdList.add(methodDefinition);
		}
		
		return true;
	}

           

有了依賴關系 在利用反射機制bean注解的方法時,若是有一個方法的參數 它已經被放到beanpool裡面我們應該怎樣處理呢

看代碼:

void matchDependance(Class<?> klass, OnReadyBeanMethodDefinition onReady) {
		List<BeanMethodDefinition> bmdList = parameterDependance.get(klass);
		if (bmdList == null) {
			return;
		}
		for (BeanMethodDefinition bmd : bmdList) {
//即将  對應處理了的參數 後面的BeanMethodDefinition裡面的 paraCount--;
			int paraCount = bmd.decrease();
			if (paraCount == 0) {
				onReady.in(bmd);
			}
// 因為 這個BeanMethodDefinition對應的此參數已經滿足 是以此參數對應的//List<BeanMethodDefinition>裡面就不應該有此BeanMethodDefinition			bmdList.remove(bmd);
			if (bmdList.isEmpty()) {
				parameterDependance.remove(klass);
//parameterDependce 容器中每處理完一個參數鍵對應的list就該銷毀整條記錄
			}
		}
	}


           

(2)OnReadyBeanMethodDefinition 裡面存着 已經處理好的方法

(3)MethodBeanDefination

private Class<?> klass;

private Object object;

private Method method;

private int paraCount;

其中: 用map的鍵不可以重複的特性來計算有的參數類型個數

protected Method getMethod() {
		Map<Class<?>, Object> map = new HashMap<Class<?>, Object>();
		Parameter[] parameters = method.getParameters();
		for (Parameter parameter : parameters) {
			map.put(parameter.getType(), null);
		}
		paraCount = map.size();
		
		return method;

           

反觀包掃描裡面的代碼

先掃描,掃描到普通類時處理完存入BeanPool;掃描到方法時先分情況儲存下來,無參不用進行參數互相依賴 關系的處理

,帶參的先儲存到parameterDependce容器中等加工完成後在加入到ready容器中,然後對reday容器中準備好的方法進行處理在儲存到map中以供使用。

collectBeanMethod 裡面形成了一個個的MethodBeanDefination

并且 形成調用 ParameterDependance裡面的 addDependce 方法

底下的 processBeanMethod 利用反射機制執行 收集的方法 并将

結果 作為BeanPool裡面的鍵,值為其defination

這樣也放入BeanPool裡面

BeanPool準備完成 就可以進行注入 其中 Inject的方法 與getBean方法互相調用

這樣就實作了方法的注入!

繼續閱讀