对于spring中IOC和AOP的理解及代码简单实现

IoC(Inversion of Control):
在传统的java程序编写中如果调用方法或类者,必须要对被调用者进行实例化,即必须要通过new 被调用者类,才能对被调用者类中的方法、成员进行操作。在开发某一个项目时必然会出现很多类来完善项目的需求,并且类与类之间有很多的交互和依赖,代码将会很变得很难高度耦合和有效的维护。spring中的IoC便解决了这一问题。IoC即控制反转,它主要是将控制权原本由被调用者转换成spring的容器。也就是说由spring生成(实例化)这些对象,并控制这些类的调用。IoC还有一种叫法是DI(Dependency Injection),即依赖注入。在spring容器启动的时候就会自动的将一些类、方法、成员装入一个bean容器中,在之后调用者调用这些类、方法、成员时就不需要再次实例化。这样可以避免多次对被调用者进行实例化,调用者不需要再像之前有那么多重复的操作。
简单来说,spring的IoC就好比是一个餐厅,在餐厅开饭之前厨师已经通过之前的很多步骤做好了很多菜。等到开饭后,很多买饭者可以任意挑选自己喜欢吃的菜,但是不需要关心这些菜的做法及过程,只管尽情的享用即可。
AOP(Aspect Oriented Programming):
AOP即面向切面编程。个人理解是将一个本身完整的东西,但是因为需要对操作者增加一些权限,必须将这个东西切开,然后给里面加一些想要的拦截。比如说一个酒店服务员你可以给顾客端茶递水,但是一个酒店打扫卫生的员工就不允许给顾客端茶递水。所以就需要酒店经理提前给这些员工分配自己的工作范围。
spring实现AOP需要引入java中的代理,其主要目的是为了增加拦截器。在java中有两种代理方式,JDK代理和CGLIB代理。前者代理需要本实现一个接口,在代理这个类时只能代理接口中的类。后者代理不需要实现接口,但是对于本类中的final方法不能进行代理。具体代理方式自行查看。
先看看我实现IOC和AOP的总体思路框图
在这里插入图片描述
接下来看看代码的简单实现
首先是一个SatProxy类,其中共有三个成员,成员的get()和set()方法就不写了

private Object proxy;			//代理对象//代理类的本对象
private Object object;			//代理类的本对象
private boolean isInjection;	//判断成员是否注入

在这个类中还有三个拦截器方法。分别为doBefore()、doAfter()、dealException()。其主要是为了对一些需要拦截的方法进行置前、置后、异常拦截(为了简单只写了这三个拦截方法,spring中还有其他拦截方法)

	protected boolean doBefore(Object[] args, Class<?> klass, Method method) {
		IntercepterFactory intercepterFactory = new IntercepterFactory();		//拦截器工厂
		IntercepterTargetDefination itd = new IntercepterTargetDefination
					(klass, method);		//通过从ProxyFactory中传过来的method,klass确定目标拦截方法
		List<IntercepterMethodDefination> intercepterMethodList = 
				intercepterFactory.getBeforeMethodList(itd);		//通过目标拦截方法找到拦截方法List
		if (intercepterMethodList == null) {			//如果没有找到相关的拦截器
			return true;
		}
		for (IntercepterMethodDefination imd : intercepterMethodList) {
			Method intercepterMethod = imd.getMethod();
			Object object = imd.getObject();
			boolean result = false;
			try {
				result = (boolean)intercepterMethod.invoke(object, args);	//反射拦截方法
				return result;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return true;
	}

上面代码中提到了IntercepterFactory类,那我们先来看看这个类
在这里插入图片描述
在上面的框图中所提到的InteecepterMethodDefination类中有成员的get()和set()方法、IntercepterTargetDefination类有equas()方法
在下面的代码中只写出了addBeforeMap()、getbeforeMethodList()方法,其他的addAfterMap()、addExceptionMap()、getbeforeMethodList()、getbeforeMethodList()与它们相似,这里就不再写出来

public class IntercepterFactory {
	private static final Map<IntercepterTargetDefination, List<IntercepterMethodDefination>> beforeMap;
	private static final Map<IntercepterTargetDefination, List<IntercepterMethodDefination>> afterMap;
	private static final Map<IntercepterTargetDefination, List<IntercepterMethodDefination>> exceptionMap;

	static {
		beforeMap = new HashMap<>();
		afterMap = new HashMap<>();
		exceptionMap = new HashMap<>();
	}
	private void addIntercepterMap(
				Map<IntercepterTargetDefination, List<IntercepterMethodDefination>> map,
				IntercepterTargetDefination intercepterTarget,
				IntercepterMethodDefination intercepterMethod) {
		List<IntercepterMethodDefination> methodList = map.get(intercepterTarget);
		if (methodList == null) {		//若methodLIst没有产生则执行以下代码,否则直接将拦截器加入List
			synchronized (IntercepterFactory.class) {	//锁住该类
				if (methodList == null) {
					methodList = new ArrayList<>();
					map.put(intercepterTarget, methodList);
				}
			}
		}
		methodList.add(intercepterMethod);
	}
	//	往Map中添加成员
	protected void addBeforeMap(IntercepterTargetDefination intercepterTarget,
			IntercepterMethodDefination intercepterMethod) {
		addIntercepterMap(beforeMap, intercepterTarget, intercepterMethod);
	}
	//	通过目标拦截方法获取拦截方法
	protected List<IntercepterMethodDefination> getBeforeMethodList(
			IntercepterTargetDefination intercepterTarget) {
		return beforeMap.get(intercepterTarget);
	}
}

在上述类中使用synchronized,是为了保证三个List都是单例的。也就是执行一次所有的方法只能各有一个这样的List,也就是说将所有的before拦截、after拦截、exception拦截都各自保存在一个List中。其中三个Map也都应该是单例的
在ProxyFactory类中产生CGLIB/JDK代理,其中有SatProxy类的成员,并有其set()、get()方法。

public class ProxyFactory {
	
	private SatProxy satProxy;
	
	protected <T> T getCGLProxy(Object object, Class<?> klass) {
		T proxy = CGLProxy(object, klass);
		satProxy = new SatProxy();
		satProxy.setProxy(proxy);	//将代理加入SatProxy类中
		satProxy.setObject(object);		//将原对象加入SatProxy类中
		
		return proxy;
	}
	
	@SuppressWarnings("unchecked")
	private <T> T CGLProxy(Object object, Class<?> klass) {		//产生CGLIB代理
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(klass);
		MethodInterceptor methodInterceptor = new MethodInterceptor() {
			
			@Override
			public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
				Object result = invokeMethod(klass, object, method, args);		//调用本类下的反射方法
				
				return result;
			}
		};
		enhancer.setCallback(methodInterceptor);
		return (T) enhancer.create();
	}
	//	反射方法
	private Object invokeMethod(Class<?> klass, Object object, Method method, Object[] args) throws Throwable {
		Object result = null;
		// 置前拦截
		if (satProxy.doBefore(args, klass, method) == false) {			
			return null;
		}
		try {
			result = method.invoke(object, args);
			// 置后拦截
			result = satProxy.doAfter(result, klass, method);
		} catch (Throwable e) {
			// 异常拦截
			satProxy.doDealException(klass, e, method);
			throw e;
		}
		
		return result;
	}
}

产生JDK的代理的方法与产生CGLIB代理的方法相似
在ProxyBeanFactory类中的方法调用ProxyFactory类中的方法。在下面的代码中只有产生CGLIB代理的方法

public class ProxyBeanFactory {
	private static final Map<String, SatProxy> beanMap;	//将扫描到的类或方法产生的代理和类名称保存
	private static final Map<String, String> beanNameMap;	//将扫描到的类或方法注解中带有的name和类名字保存
	static {
		beanMap = new HashMap<>();
		beanNameMap = new HashMap<>();
	}
	protected void addBeanNameMap(String beanName, String klassName) throws Exception {
		String orgClassName = beanNameMap.get(beanName);
		if(orgClassName != null) {		//如果已经加入Map就抛出异常
			throw new ClassNameAlreadyExistException("bean(" + beanName + ")重复");	
		}
		beanNameMap.put(beanName, klassName);
	}
	protected SatProxy getSatProxy(String klassName) {
		return beanMap.get(klassName);
	}
	protected <T> T getProxy(Class<?> klass) {
		SatProxy satProxy = beanMap.get(klass.getName());
		return satProxy.getProxy();		//返回一个代理,注意:不是satProxy
	}
	protected void creatCGLProxy(Class<?> klass) throws Exception {	//产生一个代理
		cglProxy(klass.newInstance(), klass);
	}
	private void cglProxy(Object object, Class<?> klass) {
		String klassName = klass.getName();
		SatProxy satProxy = beanMap.get(klassName);
		if(satProxy != null) {			//如果已经存在,直接return
			return;
		}
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.getCGLProxy(object, klass);	//真正的产生一个代理
		beanMap.put(klassName, proxyFactory.getSatProxy());		//将产生的代理和类名称加入Map
	}
}

在上述类中之所以将Map写为static final的是为了保证每次产生的Map都是单例的,换句话说是为了将扫描到的类或方法都存到同一个Map中
我们把上述这些基本的类准备好之后就可以开始使用BeanFactory类扫描包(可能会觉得代码有点长,但是每一步都不可少)

public class BeanFactory {
	
	public BeanFactory() {
	}
	
	public static void scanPackage(String packageName) {
		ProxyBeanFactory proxyBeanFactory = new ProxyBeanFactory();	//产生一个对象
		List<BeanMethodDefination> beanMethodList = new ArrayList<>();	//保存有参数的方法(后面会讲BeanMethoddefination类)
		new PackageScanner() {		//扫描包(自己的工具)
			@Override
			public void dealClass(Class<?> klass) {		//扫描包中类
				if (!klass.isAnnotationPresent(Component.class)) {	//如果没有@Component注解,直接return
					return;
				}
				Component component = klass.getAnnotation(Component.class);
				String name = component.name();		//得到注解中的name
				try {
					String klassName = klass.getName();
					createBean(proxyBeanFactory, klass, null, name);		//创建一个该类的代理(加入beanMap)
					SatProxy satProxy = proxyBeanFactory.getSatProxy(klassName);
					Object object = satProxy.getObject();		//得到Klass类的原对象
					
					Method[] methods = klass.getDeclaredMethods();		//得到该类的所有方法
					for (Method method : methods) {
						if (!method.isAnnotationPresent(Bean.class)) {		//若该方法中没有@Bean注解,则继续扫描下一个方法
							continue;
						}
						invokeBeanMethod(proxyBeanFactory, object, method, beanMethodList);	//调用本类的方法
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}.packageScan(packageName);
		for (BeanMethodDefination beanMethod : beanMethodList) {	//当包扫描完之后,将带有参数的方法继续产生代理
			Class<?> returnType = beanMethod.getReturnType();
			Parameter[] parameters = beanMethod.getParameters();
			Object object = beanMethod.getObject();
			Method method = beanMethod.getMethod();
			String name = beanMethod.getNike();
			
			try {
				Object result = invokeLastMethod(proxyBeanFactory, object, parameters, method);		//本类中的方法,后面讲到
				createBean(proxyBeanFactory, returnType, result, name);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	private static void invokeBeanMethod(ProxyBeanFactory proxyBeanFactory, Object object,
			Method method, List<BeanMethodDefination> beanMethodList) throws Exception{
		Class<?> returnType = method.getReturnType();		//得到该类的返回类型
		if (returnType.equals(void.class)) {		//若返回值为void,则不处理
			return;
		}
		Bean bean = method.getAnnotation(Bean.class);
		String name = bean.name();
		Parameter[] parameters = method.getParameters();		//得到该方法的参数
		if (parameters.length <= 0) {		//若没有参数,则直接反射,并创建一个代理加入beanMap
			Object result = method.invoke(object);
			createBean(proxyBeanFactory, returnType, result, name);
		} else {			//否则,先加入List<BeanMethodDefination>中
			beanMethodList.add(new BeanMethodDefination(object, parameters,
					returnType, name, method));
		}
	}
	
	private static void createBean(ProxyBeanFactory proxyBeanFactory, Class<?> klass,
			 Object object, String name) throws Exception {		//创建代理
		if (object != null) {
			proxyBeanFactory.creatCGLProxy(object);
		} else {
			proxyBeanFactory.creatCGLProxy(klass);
		}
		if (name.length() > 0) {		//若name不为空值,则将该类的名称和该name加入beanNameMap中
			proxyBeanFactory.addBeanNameMap(name, klass.getName());
		}
	}
	
	private static Object invokeLastMethod(ProxyBeanFactory proxyBeanFactory, Object object,
			 Parameter[] parameters, Method method) throws Exception {
		Object result = null;
		int paraCount = parameters.length;
		Object[] paras = new Object[paraCount];
		for (int index = 0; index < paraCount; index++) {
			Parameter parameter = parameters[index];
			String klassName = parameter.getType().getName();	//得到参数类型的名称
			SatProxy satProxy = proxyBeanFactory.getCGLProxy(klassName);//通过参数类型名称得到参数类型的代理
			Object beanObject = satProxy.getObject();		//得到代理类的原对象
			if (beanObject == null) {
				continue;
			}
			paras[index] = beanObject;
		}
		result = method.invoke(object, paras);		//通过代理原对象构成的参数进行反射得到方法的值
		
		return result;
	}
	
	private static void injectBean(ProxyBeanFactory proxyBeanFactory, Class<?> klass,
			 Object object) {
		Field[] fields = klass.getDeclaredFields();		//得到该类中的所有成员
		SatProxy selfProxy = proxyBeanFactory.getCGLProxy(klass.getName());
		selfProxy.setInjection(true);		//将inJection改为true
		
		for (Field field : fields) {
			if (!field.isAnnotationPresent(Autowired.class)) {		//若成员没有@Autowired注解
				continue;
			}
			Class<?> fieldType = field.getType();	//得到成员的类型
			SatProxy fieldProxy = proxyBeanFactory.getCGLProxy(fieldType.getName());	//得到成员类型的SatProxy
			if (!fieldProxy.isInjection()) {			//若成员类型没有注入,则递归调用本函数
				injectBean(proxyBeanFactory, fieldType, object);
			}
			field.setAccessible(true);		//设置该成员为可改
			try {
				field.set(object, fieldProxy.getObject());		//更改
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static <T> T getProxyBeanFactory(Class<?> klass) {		//指定类中注入成员
		ProxyBeanFactory proxyBeanFactory = new ProxyBeanFactory();
		SatProxy satProxy = proxyBeanFactory.getSatProxy(klass.getName());//指定类需要带@Conponent注解
		if (!satProxy.isInjection()) {		//若该类没有注入成员
			injectBean(proxyBeanFactory, klass, satProxy.getObject());
		}
		T beanProxy = satProxy.getProxy();
		return beanProxy;		//得到代理
	}

}

BeanMethodDefination类中有(Object、Method、Parameter[]、Class<?>(returnType)、String(name))以及get()和set()方法
上面提到@Component、@Bean、@Autowired注解,其中三个分别是在类、方法、成员中使用的注解。这里给出了一个注解,其余的注解只是Target不同

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
	String name() default "";
}

因为在扫描类或方法时是无序的,所以不能保证自己想用的类已经产生了代理。在BeanFactory类中扫描带方法的注解时,有的方法中可能含有参数,并且这个参数的类型在调用这个方法之前不确定是否已经产生代理,若参数类型没有产生代理就反射该方法就会产生异常。为了保证每次反射方法时都能正常执行,在BeanFactory类中扫描类中的方法时,如果该方法没有参数,就直接进行反射。如果有参数则先存入List中,等包中所有的类都扫描完之后,再将这个List中的每一个方法进行遍历并产生代理存入beanMap中。在此代码实现中规定如果方法的返回值类型为void,则不执行它。也就是说需要注入的方法不能没有返回值,并且返回值不能为八大基本类型。
在注入成员时,并不知道该成员的类是否已经注入。有时可能会出现a成员的A类没有注入,当注入A类时发现A类中依然有需要注入的b成员,当注入B类时又发现需要注入C类的c成员…(即循环依赖)在这种情况下,如果直接将a成员注入,则会抛出异常。为了解决这个问题,在执行该方法时进行判断,如果该成员的类已经注入,则直接注入该成员。如果没有注入,则继续调用BeanFactory类中的injectBean()方法(即递归调用)
前面讲的BeanFactory类主要是我实现IOC的核心代码。下面讲的IntercepterScanner类是我实现AOP(添加拦截器)的核心代码

public class IntercepterScanner {
	public IntercepterScanner() {
	}
	public static void scanIntercepter(String packageName) {	//扫描包
		new PackageScanner() {
			@Override
			public void dealClass(Class<?> klass) {
				if (!klass.isAnnotationPresent(Aspect.class)) {	//@Aspect注解,return
					return;
				}
				IntercepterFactory intercepterFactory = new IntercepterFactory();	//前面讲过IntercepterFactory类
				try {
					Object object = klass.newInstance();
					Method[] methods = klass.getDeclaredMethods();
					for (Method method : methods) {			//遍历含有注解类中的方法
						if (method.isAnnotationPresent(Before.class)) {			//如果有@Before注解
							Before before = method.getAnnotation(Before.class);
							dealBeforeIntercepter(intercepterFactory, method, before, klass, object);
						} else if (method.isAnnotationPresent(After.class)) {	//如果有@After注解
							After after = method.getAnnotation(After.class);
							dealAfterIntercepter(intercepterFactory, method, after, klass, object);
						} else if (method.isAnnotationPresent(ThrowsException.class)) {	//如果有@Exception注解
							ThrowsException exception = method.getAnnotation(ThrowsException.class);
							dealExceptionIntercepter(intercepterFactory, method, exception, klass, object);
						} else {
							return;
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}

			}
		}.packageScan(packageName);
	}
	private static void dealBeforeIntercepter(IntercepterFactory intercepterFactory, Method method,
			Before before, Class<?> klass, Object object) throws Exception{	//处理带有@Before注解的方法
		
		Class<?> returnType = method.getReturnType();
		if (returnType.equals(Boolean.class)) {	//如果该方法的返回值类型不为Boolean,抛出异常
			throw new BadReturnTypeException("方法(" + method + ")的返回值类型应为Boolean");
		}
		Class<?> targetKlass = before.klass();	//得到注解中传过来目标方法的类
		Class<?>[] parameterTypes = method.getParameterTypes();	//得到注解中传过来的目标方法名称
		Method targetMethod = targetKlass.getMethod(before.method(), parameterTypes);	//得到注解中传过来的目标方法中参数类型
		IntercepterMethodDefination intercepterMethod = new IntercepterMethodDefination(klass, method, object);	//得到拦截方法
		IntercepterTargetDefination intercepterTarget = new IntercepterTargetDefination(targetKlass, targetMethod);	//得到拦截目标方法
		intercepterFactory.addBeforeMap(intercepterTarget, intercepterMethod);		//将得到的方法加入相应的拦截器Map
	}
	
	private static void dealAfterIntercepter(IntercepterFactory intercepterFactory, Method method, 
			After after, Class<?> klass, Object object) throws Exception {		//处理带有@After注解的方法
		Class<?>[] parameterTypes = after.parasType();		//得到目标方法中的参数类型
		Class<?> returnType = method.getReturnType();		//得到拦截方法的返回值类型
		Class<?> targetKlass = after.klass();							//得到目标方法的类
		Method targetMethod = targetKlass.getMethod(after.method(), parameterTypes);//通过目标方法名称和参数类型反射得到目标方法
		Class<?> targetReturnType = targetMethod.getReturnType();	//得到目标方法的返回值类型
		if (!returnType.equals(targetReturnType)) {		//如果目标方法的返回值类型与拦截方法的返回值类型不同时,抛出异常
			throw new BadReturnTypeException("方法(" + method + ")的返回值类型应与目标方法返回值类型不一样");
		}
		IntercepterMethodDefination intercepterMethod = new IntercepterMethodDefination(klass, method, object);	//得到拦截方法
		IntercepterTargetDefination intercepterTarget = new IntercepterTargetDefination(targetKlass, targetMethod);	//得到目标拦截方法
		intercepterFactory.addAfterMap(intercepterTarget, intercepterMethod);		//加入相应的Map
	}
	private static void dealExceptionIntercepter(IntercepterFactory intercepterFactory, Method method, 
			ThrowsException exception, Class<?> klass, Object object) throws Exception {	//处理带有@Exception注解的方法,与前面的方法相似
		Class<?> returnType = method.getReturnType();
		if (returnType.equals(void.class)) {
			throw new BadReturnTypeException("方法(" + method + ")的返回值类型应为void");
		}
		Class<?>[] parameterTypes = method.getParameterTypes();
		if (parameterTypes.equals(new Class<?>[]{Throwable.class})) {
			throw new BadParameterTypesException("方法(" + method + ")的参数类型不正确");
		}
		Class<?> targetKlass = exception.klass();
		Method targetMethod = targetKlass.getMethod(exception.method(), parameterTypes);
		IntercepterMethodDefination intercepterMethod = new IntercepterMethodDefination(klass, method, object);
		IntercepterTargetDefination intercepterTarget = new IntercepterTargetDefination(targetKlass, targetMethod);
		intercepterFactory.addExceptionMap(intercepterTarget, intercepterMethod);
	}
	
}

上面类中提到@Before、@After、@Exception注解,这里给出@After的代码

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface After {
	Class<?> klass();
	String method();
	Class<?>[] parasType() default {Class.class};
}

在@After注解中有目标方法的参数类型,其默认值为Class,这是为了通过目标方法的参数类型及方法名称反射出目标方法,并判断目标方法的返回值与拦截方法的返回值是否一致。若不一致,则要抛出异常。其他两个注解与@After相似,但是不需要参数类型,因为他们的拦截方法的返回值都已经确定。即Before拦截的方法的返回值为boolean,Exception拦截的方法无返回值

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值