Spring Framework中IOC&AOP手动模拟实现;基于责任链模式的AOP拦截器链;IOC循环依赖的递归处理法;

博文说明:

往期有一篇博文是关于手动模拟实现IOC的,这期在此基础上融合了AOP部分,并且做出了些许优化。读者可以选择先理解IOC部分,再选择与AOP部分一起理解。本期博文的IOC部分与往期单独的IOC博文中的实现原理和方式大体相同,本期将先讲述AOP部分。

关于AOP

Spring AOP(面向切面编程)的目的是在程序开发中,为了解决一些系统层面上的问题,比如做日志、权限管理等等的事务管理问题而设计的。并且这种方式配合IOC的代码解耦性很高,是体现面向切面编程的一个经典的例子。

Spring 框架中IOC与AOP的体现即为自动注入机制与拦截器机制。他们都是通过注解方式进行初始化的。Spring AOP的核心是围绕代理机制为核心进行设计的,其是在具体的一个目标方法的执行前、、执行后、发生异常这几种情况下,进行一定的事务管理(权限判断、做日志等)。Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理。作者以实现其核心功能和思想为目的,本次的实现将只使用CGLIB类模式的代理机制。以后此博文可能会更新。

所用到的工具及jar包

包扫描工具(往期博文有介绍)
cglib Jar包

正文

1、拦截器注解及其相关POJO介绍:

@Aspect

/**
 * @Aspect注解
 * 其声明的类中存放了各种拦截器。
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Aspect {
   
}

@Before

/**
 * @Before注解
 * 其标注的方法为前置拦截器方法。在相关操作执行前进行的前置拦截(参数拦截)。
 * 在使用此注解拦截器方法时必须声明:
 * 	目标方法名
 * 	目标方法所在的类
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Before {
   
	Class<?> klass();
	String method();
}

前置拦截器的作用就是拦截具体方法执行前所需要的参数,对那些参数进行检查,判断此操作还能不能进行下去。所以前置拦截器方法的返回值是boolean类型,其参数与所拦截的目标方法的参数是一致的。这样,我们就能通过目标类和前置拦截方法的参数,使用反射机制反射到目标方法对象。

@After

/**
 * @After注解
 * 其标注的方法为后置拦截器方法。在相关操作执行完后进行的后置拦截(结果拦截)。
 * 注解后置拦截器方法时必须声明:
 * 	目标方法所在的类
 * 	目标方法名
 * 	目标方法的参数数组
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface After {
   
	Class<?> klass();
	String method();
	Class<?>[] parameterTypes();
}

@ThrowException

/**
 * @ThrowException注解
 * 其标注的方法为异常拦截器方法。在相关操作执行中发生异常时进行的异常拦截。
 * 注解异常拦截器方法时必须声明:
 * 	目标方法所在的类
 * 	目标方法名
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ThrowException {
   
	Class<?> klass();
	String method();
}

拦截目标:IntercepterTargetDefination

/**
 * 拦截目标类
 * 其中包含被拦截目标方法对象及其所在的类对象。
 * @author Lconf
 *
 */
public class IntercepterTargetDefination {
   
	private Class<?> targetClass;
	private Method targetMethod;
	
	//带参构造及getters、setters
	}

拦截器:IntercepterMethodDefination :

/**
 * 拦截器定义。其中包含拦截器所在的类名、方法对象、所在类的对象
 * @author Lconf
 *
 */
public class IntercepterMethodDefination {
   
	private Class<?> klass;//拦截器所在的类
	private Method method;//拦截器方法
	private Object object;//拦截器方法所在的类的实例,以供在拦截时调用
	//带参构造、getters、setters
	}

我们在包扫描阶段通过扫描注解,针对扫描出的拦截器进行分类、存储。下面介绍扫描过程类与拦截器工厂、拦截器所在工厂中的包装类。

2、拦截器的扫描:IntercepterScanner类

代码有点长,但这个类就只有一个提供给外面用的方法
作者也在每个方法之前都加上了详细的注释。


public class IntercepterScanner {
   

	/**
	 * 扫描出拦截器们所在的类并逐个对其进行处理,加入到拦截器工厂中
	 * @param packageName 包名称
	 */
	public static void intercepterScanner(String packageName) {
   
		new PackageScanner() {
   
			
			@Override
			public void dealClass(Class<?> klass) {
   
				if (!klass.isAnnotationPresent(Aspect.class)) {
   
					return;
				}
				//aspect注解的类中集合了各种各样的拦截器。我们将他归类、添加。
				try {
   
					Object object = klass.newInstance();
					Method[] methods = klass.getDeclaredMethods();
					for (Method method : methods) {
   
						try {
   
							if (method.isAnnotationPresent(Before.class)) {
   
								Before before = method.getAnnotation(Before.class);
								addBeforeInterceptor(klass, object, method, before);
							} else if (method.isAnnotationPresent(After.class)) {
   
								After after = method.getAnnotation(After.class);
								addAfterInterceptor(klass, object, method, after);
							} else if (method.isAnnotationPresent(ThrowException.class)) {
   
								ThrowException throwException = method.getAnnotation(ThrowException.class);
								addExceptionInterceptor(klass, object, method, throwException);
							}
						} catch (Exception e) {
   
							e.printStackTrace();
						}
					}
				} catch (Exception e) {
   
					e.printStackTrace();
				}
			}
		}.packageScan(packageName);
	}

	/**
	 * 添加异常拦截器到拦截器工厂中
	 * @param klass 拦截器所在类
	 * @param object 拦截器所在类的实例
	 * @param method 拦截器方法本身
	 * @param throwException 扫描到的注解对象,用于反射构建出IntercepterTargetDefination对象
	 * @throws Exception
	 */
	private static void addExceptionInterceptor(Class<?> klass, Object object, Method method,
			ThrowException throwException) throws Exception {
   
		//异常拦截器是在相应操作异常时,将具体异常传递给所有该操作的异常拦截器。
		//所以异常拦截器的返回值类型是void,参数类型是Throwable!
		Class<?> returnType = method.getReturnType();
		Class<?>[] paras = method.getParameterTypes();
		
		if(returnType.equals(void.class) || paras.length != 1 || paras[0] != void.class) {
   
			throw new Exception("拦截器操作\" " + method + "\"不符合规范!");
		}
		Class<?> targetClass = throwException.klass();
		String targetMethodName = throwException.method();
		Method targetMethod = klass.getDeclaredMethod(targetMethodName, Throwable.class);
		IntercepterTargetDefination itd = new IntercepterTargetDefination(targetClass, targetMethod);
		IntercepterMethodDefination imd = new IntercepterMethodDefination(klass, method, object);
		IntercepterFactory intercepterFactory = new IntercepterFactory();
		intercepterFactory.addExceptionIntercepter(itd, imd);
	}

	/**
	 * 添加后置拦截器到拦截器工厂中
	 * @param klass 拦截器所在类
	 * @param object 拦截器所在类的实例
	 * @param method 拦截器方法本身
	 * @param after 扫描到的注解对象,用于反射构建出IntercepterTargetDefination对象
	 * @throws Exception
	 */
	private static void addAfterInterceptor(Class
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值