模仿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
如图:


(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方法相互调用

这样就实现了方法的注入!

全部评论

相关推荐

11-09 14:54
已编辑
华南农业大学 产品经理
大拿老师:这个简历,连手机号码和照片都没打码,那为什么关键要素求职职位就不写呢? 从上往下看,都没看出自己到底是产品经理的简历,还是电子硬件的简历? 这是一个大问题,当然,更大的问题是实习经历的描述是不对的 不要只是去写实习流程,陈平,怎么去开会?怎么去讨论? 面试问的是你的产品功能点,是怎么设计的?也就是要写项目的亮点,有什么功能?这个功能有什么难处?怎么去解决的? 实习流程大家都一样,没什么优势,也没有提问点,没有提问,你就不得分 另外,你要明确你投的是什么职位,如果投的是产品职位,你的项目经历写的全都是跟产品无关的,那你的简历就没用 你的面试官必然是一个资深的产品经理,他不会去问那些计算机类的编程项目 所以这种四不像的简历,在校招是大忌
点赞 评论 收藏
分享
三年之期已到我的offer快到碗里来:9硕都比不上9本
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务