文章目录
博文说明:
往期有一篇博文是关于手动模拟实现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