利用注解机制简单的自定义实现Spring中IOC和DI

实现Spring中的IOC和DI其实也不是很难,关键是要找到地方下手,我们可以先仿照Spring中的注解声明
1.IOC操作
Component:用于实现ioc控制反转,属性你可以自己定义 但是本次实现没有使用
Service:专门用于controller注解
2.DI
Autowired:利用该注解实现将对象注入到属性 ,也就是自动装配
Bean:将对象注入到方法
核心是ApplicationContext:里面将所有的托管bean都存到一个Map中,实现包扫描,和注入都在这个类中实现
提供一个genBean()方法获取已经托管好的Bean
在这里插入图片描述包结构在这里插入图片描述
然后从Spring中的入口类 appConfig类开始 我们发现中间最主要的是 ApplicationContext类,我们可以这么想 ,假设将我要扫描包的所有路径传入到这个类中,然后循环所有的这个包里面的内容 将带有java后缀名的类利用反射进行实例话,然后筛选带有Component和Service的注解的的类实例话将其放到一个Map中,然后提供一个getBean()方法根据类名来获取这个类的实例 具体这个类的实现代码如下 注释写的比较详细

public class ApplicationContext implements applicationContent{
	private Class<?> clazz;//传入appconfig的class反射 因为我要将其看作是一个配置文件读取要扫描哪一个包
	//存储bean
	Map<String, Object> map=new HashMap<String, Object>();
	//根据bean来获取
	@Override
	public Object getBean(String beanname) {
		// TODO Auto-generated method stub
		return map.get(beanname.toLowerCase());
	}
	//扫描注解   将bean进行托管
	public ApplicationContext(Class<?> clazz) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException{
		this.clazz=clazz;//这里即是sppConfig类的反射实例
		Annotation [] a=clazz.getDeclaredAnnotations();//获取该反射实例上面的所有注解
		//我这里是这样的 这个方法上面有很多注解,但是这里面有一个规则,就是必须要先声明Configure注释菜进行包扫描
		int y=0;
		for (int i = 0; i < a.length; i++) {
			if(a[i] instanceof Configuration){
				//说明这个类是配置类 菜有可能去扫描到ComponentScan类 
				y++;
				//这里前面就是扫描到Configuration 	前提就是要先有Configure
			}else if(a[i] instanceof ComponentScan && y==1){
				ComponentScan comp=clazz.getAnnotation(ComponentScan.class);//获取到注解的实例
				String pkgName=comp.basePackages();//获取到注解的包路径 
				//这里要扫描这个报下面的所有路径 我这边写的路径是 com.ly 所以要变成 com/ly
				String pkgDirName = pkgName.replace('.', File.separatorChar);
				//得到绝对路径
				String user=System.getProperty("user.dir")+"/src/main/java/"+pkgDirName;
				//开始扫描所有的类
				findAll(user);//开始扫描这个包里面所有的类
			//	System.out.println(list);
			}
		}
	}
	/**
	 * 采用递归 找出这个包下面的所有的内容
	 * @param basepath
	 * @return
	 * @throws MalformedURLException
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
 public ArrayList findAll(String basepath) throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException{
		 //写终止条件
		File file = new File(basepath);
		//System.out.println(file);
		if(file==null){
			return list;
		}
		File[] fileList = file.listFiles();//将该目录下的所有文件放置在一个File类型的数组中
		//循环一个列表下面所有的文件或者是目录 ,如果是目录就就再次递归
		for (File f : fileList) {
			if (f.isDirectory()) {//判断是否为文件夹
				//递归
				findAll(f.getAbsolutePath());
			}else{
				if(f.getName().endsWith(".java")){
					//扫描到java类
					//需要截取
					String name=f.getName().substring(0,f.getName().lastIndexOf("."));
					list.add(name);//这里file.getAbsoluteFile user/java/com/ly 我只需要com.ly
					String new_name=file.getAbsoluteFile().toString().split("java/")[1].replace("/", ".");
					Class cc=Class.forName(new_name+"."+name);//获取该类的反射实例
					//===============实现类上面的注解 进行IOC托管=============================
					Annotation [] a=cc.getAnnotations();
					for (Annotation annotation : a) {
						//我这里没有将 Component 和Service注解进行分开处理  只要是出现该类注解就直接将其托管
						if(annotation instanceof Component 
								|| annotation instanceof Sercice){
							//说明要进行装载 先判断是不是有这个对象
						//	Component comp=clazz.getAnnotation(Component.class);//获取到注解
							//有这个注解 所以我就要将类托管起来  注意这里的键 可以随你自己去指定 我这里是使用这个类的类名的小写做键 
							map.put(name.toLowerCase(), cc.newInstance());
						}
					}
//========================实现属性上面的注解解析=========================================
					Method []me=cc.getDeclaredMethods();
					//循环所有的方法
					for (Method method : me) {
						//获取这个方法上面的所有注解
						Annotation [] ann=method.getAnnotations();
						if (ann==null)
							break;
						for (Annotation annotation : ann) {
							if(annotation instanceof Bean){
								try {
									//激活这个方法 将参数传进去
									Object obj_1=method.invoke(cc, null);
								} catch (IllegalArgumentException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (InvocationTargetException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
							}
						}
						
						
					}
	//=======================对autowired注解的解析 实现DI的注入==================================
					Field[] fields=cc.getDeclaredFields();
					for (Field field : fields) {
						Annotation[] allFAnnos=field.getDeclaredAnnotations();
						for (Annotation annotation : allFAnnos) {
			//				System.out.println(annotation);
							//循环所有的注解   如果这个类的字段上面
							if(annotation instanceof Autowired){
								System.out.println("看这里"+field.getName());
								Object obj=null;//实例话对象
								//实例化类 先获取类路径
								String[] path=field.toGenericString().split(" ");
								//加载类
								Class biz_class=Class.forName(path[1]);
								if(biz_class.isInterface()){
									//看是不是一个接口 获取所有的接口
									 Class<?> [] intClass=biz_class.getInterfaces();
									 //循环所有的接口
									 for (Class<?> class1 : intClass) {
										//假设只有一个接口
										 obj=class1.newInstance();//实例话这个接口的实现类
									}
								}else{
								//实例化
								 obj=biz_class.newInstance();//实例化
								//需要将这个值复制
								// 取消语言访问检查
								field.setAccessible(true);
								//对象是cc obj就是实例话对象
								//System.out.println(field.getName().substring(field.getName().lastIndexOf("."),0).toLowerCase() );
								field.set(map.get(   field.getName()    ), obj);
								}
							}
						}
					}
				
				}
			}
	
		
	 }
		return list;
	 }
	
	

}


appconfig 入口类
在这里插入图片描述
其中用到的注解需要自己去定义 本段代码实现了 对Component和Server的托管,还实现了 Bean和Autowire上午注入,采用递归的方式去扫描包下面的每一个文件,这里需要一个注意点就是当进行autowired的时候因为涉及到给私有变量去赋值所以要加一下 field.setAccessible(true); 取消访问检查 ,还有注意getDeclaredFields();和getFields()的区别 ,getDeclaredFields一个是获取自己声明的属性,当你使用getFields去获取所有的属性的时候你会发现获取的是空,总是会报空指针异常

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值