IOC注入初步尝试

之前已经完成了代理的获取,在此基础上完成注入,并添加半自动化添加拦截器,简化用户使用。
首先,回顾一下之前获取代理的过程。用户给出包名称,通过扫描包,将加相应注解的类,方法,进行处理,获取代理(方法是为方法的返回值类型获取代理)。将全部代理存起来放在map中,待用。
接着来实现我们今天的注入。

一、注入

用户通过类名字,获取代理。而我们第一步要判断这个类是否被处理过,看它有没有加相应的注解,如果没有加,那就不存在下一步了。第二步取出代理,注入。给这个类中的全部成员注入值,值就是该类的ProxyClass类中的object成员。然后就可以将处理好的代理给用户了。用户得到代理,直接使用即可。
问题一(ProxyClass类中的object和proxy):
运行一个带参方法的时候肯定是给它所需要的值,然后运行。ProxyClass类中的object成员是有值的,这个值是用户给的,我们当时把值存下来做object成员了。所以现在运行的时候要用ProxyClass类中的object成员,拦截时才使用代理,不要弄混。
问题二(单例模式):
这里的单例不同于我们平常的单例模式。本次代码中,默认每一个类仅有一个代理,即只有一个ProxyClass类,是单例的。若有多个则需要另行处理。
问题三(方法的运行):
产生代理的时候,我们写了invoke,但事实上,这一段产生代理的时候并不运行,到用户使用代理运行方法的时候,这一段才运行,invoke并拦截。

//BeanFactory类中
	/**注入   
	 * @param <proxyBeanFactory> 工具 
	 * @param <object> 需要注入的类的对象
	 * */
	private static void injection(ProxyBeanFactory proxyBeanFactory, 
			Object object) {
		//得到全部字段 (成员)
		Field[] fields = object.getClass().getDeclaredFields();
		
		for(Field f : fields) {
			if(!f.isAnnotationPresent(Autowired.class)) {
				return;
			}
			//获取该类的ProxyClass 类
			ProxyClass klassProxyClass = proxyBeanFactory.getProxyClass(object.getClass().getName());
			//设置注入成员为true
			klassProxyClass.setInject(true);
			//判断成员的类是否注入,没有继续处理
			ProxyClass fieldProxyClass = proxyBeanFactory.getProxyClass(f.getType().getName());
			if(!fieldProxyClass.isInject()) {
				injection(proxyBeanFactory, 
						fieldProxyClass.getObject());
			}
		
			f.setAccessible(true);
			try {
			//将值注入
				f.set(object, fieldProxyClass.getProxy());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	public static <T> T getBean(Class<?> klass) {
		//判断该类是否有注解
		if(!klass.isAnnotationPresent(Component.class)){
			System.out.println("该类没有注解");
			return null;
		}
		
		//获取代理
		ProxyBeanFactory proxyBeanFactory = new ProxyBeanFactory();
		ProxyClass proxyClass = proxyBeanFactory.getProxyClass(klass.getName());
		
		//是否注入,注入成员
		if(!proxyClass.isInject()) {
			injection(proxyBeanFactory,proxyClass.getObject());
		}
		//将注入好的代理返回
		return (T) proxyClass.getProxy();
	}

问题四(循环依赖):
循环依赖问题是指A类有B类的成员,B类有C类的成员,C类有A类的成员,形成一个环,注入是A等B注入,B等C注入,C等A注入,陷入死循环,此处为了解决这个问题,我们给 proxyClass类中加了一个Inject成员,未注入设为false,注入设为true,每次在未注入前就setInject为true,解决了这个问题。

主函数:

public static void main(String[] args) {
		BeanFactory.scanPackage("com.zty.student");
		ScanIntercepter.scanIntercepterMethods("com.mec.student");
		
		StudentAction action = BeanFactory.getBean(StudentAction.class);
		action.getStudentById("12345678");
	}

二、添加拦截器

类似于之前的扫描,用户给包名,扫描,处理带相应注解的,将拦截器存入map中,按一个方法对应一个拦截器链,做成键值对,存入map,即map<方法,拦截器链List>,放入intercepterFactory,而不是将其存入ProxyClass,使用时根据类和方法从intercepterFactory中取出相应的拦截器链,使用即可。

/**扫描指定包,里面加拦截器的方法已经写好注解,
	 * 根据不同注解,处理不同的拦截器方法,并把其加入不同的map中
	 * */
	public static void scanIntercepterMethods(String packageName) {
		new PackageScanner() {
			
			@Override
			//klass,是一个里面有拦截器的类
			public void dealClass(Class<?> klass) {
				if(!klass.isAnnotationPresent(Aspect.class)) {
					return;
				}
				try {
					Object object = klass.newInstance();
					Method[] methods = klass.getDeclaredMethods();
					for(Method method : methods) {
						if(method.isAnnotationPresent(Before.class)) {
							dealBeforeIntercepter(klass, object, method);
						} else if(method.isAnnotationPresent(After.class)) {
							dealAfterIntercepter(klass, object, method);
						} else if (method.isAnnotationPresent(ThrowException.class)) {
							dealExceptionIntercepter(klass, object, method);
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}.packageScan(packageName);
	}

	/**处理前置拦截器方法
	 * @param <Class> 拦截器所在的类
	 * @param <Object> 拦截器所在的类的对象
	 * @param <Method> 拦截器方法
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 * */
	private static void dealBeforeIntercepter(Class<?> klass, Object object, 
			Method method) throws Exception {
		//返回值类型不对
		if(!method.getReturnType().equals(boolean.class)) {
			throw new ReturnTypeWrongException(method.getName() + "返回值类型错误");
		}
		//要拦截的方法
		Before before = method.getAnnotation(Before.class);
		Class<?> targetClass = before.klass();
		Method targetMethod = targetClass.getMethod(before.methodName(),
				method.getParameterTypes());
		
		IntercepterMethodDefination imd = new IntercepterMethodDefination(klass, method, object);
		IntercepterTargetDefination itd = new IntercepterTargetDefination(targetClass, targetMethod);
		//存入factory
		IntercepterFactory intercepterFactory = new IntercepterFactory();
		intercepterFactory.addBeforeIntercepter(itd, imd);
	}

处理三种拦截器的方法类似,不再给出代码。

//存储拦截器的类
//其中有三个map
private static final Map<IntercepterTargetDefination,
		List<IntercepterMethodDefination>> beforeInterceptsMap;
private static final Map<IntercepterTargetDefination,
		List<IntercepterMethodDefination>> afterInterceptsMap;
private static final Map<IntercepterTargetDefination,
		List<IntercepterMethodDefination>> exceptionInterceptsMap;
	
	//添加拦截器	
private void addIntercepter(Map<IntercepterTargetDefination,
			List<IntercepterMethodDefination>> map,
			IntercepterTargetDefination itd,
			IntercepterMethodDefination imd) {
		
		List<IntercepterMethodDefination> imdList = map.get(itd);
		System.out.println(itd.getMethod() + "***"
				 + imdList);
		//这个list只能有一份,必须是单例的,每个方法只能有一个list
		if (imdList == null) {
			synchronized(IntercepterFactory.class) {
				if(imdList == null) {
					imdList = new ArrayList<>();
					map.put(itd, imdList);
				}
			}
		}
		imdList.add(imd);
	}
	
	//添加前置拦截器
	public void addBeforeIntercepter(IntercepterTargetDefination itd,
			IntercepterMethodDefination imd) {
		addIntercepter(beforeInterceptsMap, itd, imd);
	}

猜你喜欢

转载自blog.csdn.net/A_BCDEF_/article/details/83627444
今日推荐