介绍org.aspectj
包下的几个类(单独导入的Jar包)
AjTypeSystem
:从@Aspect的Class到AjType的工具类
public class AjTypeSystem { // 每个切面都给缓存上 注意:此处使用的是WeakReference 一定程度上节约内存 private static Map<Class, WeakReference<AjType>> ajTypes = Collections.synchronizedMap(new WeakHashMap<Class,WeakReference<AjType>>()); public static <T> AjType<T> getAjType(Class<T> fromClass) { WeakReference<AjType> weakRefToAjType = ajTypes.get(fromClass); if (weakRefToAjType!=null) { AjType<T> theAjType = weakRefToAjType.get(); if (theAjType != null) { return theAjType; } else { // 其实只有这一步操作:new AjTypeImpl~~~ AjTypeImpl就相当于代理了Class的很多事情~~~~ theAjType = new AjTypeImpl<T>(fromClass); ajTypes.put(fromClass, new WeakReference<AjType>(theAjType)); return theAjType; } } // neither key nor value was found AjType<T> theAjType = new AjTypeImpl<T>(fromClass); ajTypes.put(fromClass, new WeakReference<AjType>(theAjType)); return theAjType; } }
AjType
// 它继承自Java得Type和AnnotatedElement 它自己还提供了非常非常多的方法,基本都是获取元数据的一些方法,等到具体使用到的时候再来看也可以 public interface AjType<T> extends Type, AnnotatedElement { ... }
AjTypeImpl
AjTypeImpl是AjType
的唯一实现类,因为方法实在是太多了,因此下面我只展示一些觉得比较有意思的方法实现:
public class AjTypeImpl<T> implements AjType<T> { private static final String ajcMagic = "ajc$"; // 它真正传进来的,只是这个class,它是一个标注了@Aspect注解的Class类 private Class<T> clazz; private Pointcut[] declaredPointcuts = null; private Pointcut[] pointcuts = null; private Advice[] declaredAdvice = null; private Advice[] advice = null; private InterTypeMethodDeclaration[] declaredITDMethods = null; private InterTypeMethodDeclaration[] itdMethods = null; private InterTypeFieldDeclaration[] declaredITDFields = null; private InterTypeFieldDeclaration[] itdFields = null; private InterTypeConstructorDeclaration[] itdCons = null; private InterTypeConstructorDeclaration[] declaredITDCons = null; // 唯一的一个构造函数 public AjTypeImpl(Class<T> fromClass) { this.clazz = fromClass; } // 这个方法有意思的地方在于:它把所有的接口类,都变成AjType类型了 public AjType<?>[] getInterfaces() { Class<?>[] baseInterfaces = clazz.getInterfaces(); return toAjTypeArray(baseInterfaces); } private AjType<?>[] toAjTypeArray(Class<?>[] classes) { AjType<?>[] ajtypes = new AjType<?>[classes.length]; for (int i = 0; i < ajtypes.length; i++) { ajtypes[i] = AjTypeSystem.getAjType(classes[i]); } return ajtypes; } // 就是把clazz返回出去 public Class<T> getJavaClass() { return clazz; } public AjType<? super T> getSupertype() { Class<? super T> superclass = clazz.getSuperclass(); return superclass==null ? null : (AjType<? super T>) new AjTypeImpl(superclass); } // 判断是否是切面,就看是否有这个注解~~ public boolean isAspect() { return clazz.getAnnotation(Aspect.class) != null; } // 这个方法很重要:PerClause AspectJ切面的表现形式 // 备注:虽然有这么多(参考这个类PerClauseKind),但是Spring AOP只支持前三种~~~ public PerClause getPerClause() { if (isAspect()) { Aspect aspectAnn = clazz.getAnnotation(Aspect.class); String perClause = aspectAnn.value(); if (perClause.equals("")) { // 如果自己没写,但是存在父类的话并且父类是切面,那就以父类的为准~~~~ if (getSupertype().isAspect()) { return getSupertype().getPerClause(); } // 不写默认是单例的,下面的就不一一解释了 return new PerClauseImpl(PerClauseKind.SINGLETON); } else if (perClause.startsWith("perthis(")) { return new PointcutBasedPerClauseImpl(PerClauseKind.PERTHIS,perClause.substring("perthis(".length(),perClause.length() - 1)); } else if (perClause.startsWith("pertarget(")) { return new PointcutBasedPerClauseImpl(PerClauseKind.PERTARGET,perClause.substring("pertarget(".length(),perClause.length() - 1)); } else if (perClause.startsWith("percflow(")) { return new PointcutBasedPerClauseImpl(PerClauseKind.PERCFLOW,perClause.substring("percflow(".length(),perClause.length() - 1)); } else if (perClause.startsWith("percflowbelow(")) { return new PointcutBasedPerClauseImpl(PerClauseKind.PERCFLOWBELOW,perClause.substring("percflowbelow(".length(),perClause.length() - 1)); } else if (perClause.startsWith("pertypewithin")) { return new TypePatternBasedPerClauseImpl(PerClauseKind.PERTYPEWITHIN,perClause.substring("pertypewithin(".length(),perClause.length() - 1)); } else { throw new IllegalStateException("Per-clause not recognized: " + perClause); } } else { return null; } } public AjType<?>[] getAjTypes() { Class[] classes = clazz.getClasses(); return toAjTypeArray(classes); } public Field getDeclaredField(String name) throws NoSuchFieldException { Field f = clazz.getDeclaredField(name); if (f.getName().startsWith(ajcMagic)) throw new NoSuchFieldException(name); return f; } // 这个有点意思:表示标注了@Before、@Around注解的并不算真的方法了,不会给与返回了 public Method[] getMethods() { Method[] methods = clazz.getMethods(); List<Method> filteredMethods = new ArrayList<Method>(); for (Method method : methods) { if (isReallyAMethod(method)) filteredMethods.add(method); } Method[] ret = new Method[filteredMethods.size()]; filteredMethods.toArray(ret); return ret; } private boolean isReallyAMethod(Method method) { if (method.getName().startsWith(ajcMagic)) return false; if (method.getAnnotations().length==0) return true; if (method.isAnnotationPresent(org.aspectj.lang.annotation.Pointcut.class)) return false; if (method.isAnnotationPresent(Before.class)) return false; if (method.isAnnotationPresent(After.class)) return false; if (method.isAnnotationPresent(AfterReturning.class)) return false; if (method.isAnnotationPresent(AfterThrowing.class)) return false; if (method.isAnnotationPresent(Around.class)) return false; return true; } // 拿到所有的Pointcut方法 并且保存缓存起来 public Pointcut[] getDeclaredPointcuts() { if (declaredPointcuts != null) return declaredPointcuts; List<Pointcut> pointcuts = new ArrayList<Pointcut>(); Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { Pointcut pc = asPointcut(method); if (pc != null) pointcuts.add(pc); } Pointcut[] ret = new Pointcut[pointcuts.size()]; pointcuts.toArray(ret); declaredPointcuts = ret; return ret; } // 标注有org.aspectj.lang.annotation.Pointcut这个注解的方法。 相当于解析这个注解吧,最终包装成一个PointcutImpl // 主义:Spring-aop也有个接口Pointcut,这里也有一个Pointcut接口 注意别弄混了 private Pointcut asPointcut(Method method) { org.aspectj.lang.annotation.Pointcut pcAnn = method.getAnnotation(org.aspectj.lang.annotation.Pointcut.class); if (pcAnn != null) { String name = method.getName(); if (name.startsWith(ajcMagic)) { // extract real name int nameStart = name.indexOf("$$"); name = name.substring(nameStart +2,name.length()); int nextDollar = name.indexOf("$"); if (nextDollar != -1) name = name.substring(0,nextDollar); } return new PointcutImpl(name,pcAnn.value(),method,AjTypeSystem.getAjType(method.getDeclaringClass()),pcAnn.argNames()); } else { return null; } } // 最终返回的对象为AdviceImpl实现类 public Advice[] getDeclaredAdvice(AdviceKind... ofType) { ... } public Advice[] getAdvice(AdviceKind... ofType) { ... } private void initDeclaredAdvice() { Method[] methods = clazz.getDeclaredMethods(); List<Advice> adviceList = new ArrayList<Advice>(); for (Method method : methods) { Advice advice = asAdvice(method); if (advice != null) adviceList.add(advice); } declaredAdvice = new Advice[adviceList.size()]; adviceList.toArray(declaredAdvice); } // 标注了各个注解的 做对应的处理 private Advice asAdvice(Method method) { if (method.getAnnotations().length == 0) return null; Before beforeAnn = method.getAnnotation(Before.class); if (beforeAnn != null) return new AdviceImpl(method,beforeAnn.value(),AdviceKind.BEFORE); After afterAnn = method.getAnnotation(After.class); if (afterAnn != null) return new AdviceImpl(method,afterAnn.value(),AdviceKind.AFTER); AfterReturning afterReturningAnn = method.getAnnotation(AfterReturning.class); if (afterReturningAnn != null) { // 如果没有自己指定注解pointcut()的值,那就取值为value的值吧~~~ String pcExpr = afterReturningAnn.pointcut(); if (pcExpr.equals("")) pcExpr = afterReturningAnn.value(); // 会把方法的返回值放进去、下同。。。 这就是@After和@AfterReturning的区别的原理 // 它可议自定义自己的切点表达式咯 return new AdviceImpl(method,pcExpr,AdviceKind.AFTER_RETURNING,afterReturningAnn.returning()); } AfterThrowing afterThrowingAnn = method.getAnnotation(AfterThrowing.class); if (afterThrowingAnn != null) { String pcExpr = afterThrowingAnn.pointcut(); if (pcExpr == null) pcExpr = afterThrowingAnn.value(); return new AdviceImpl(method,pcExpr,AdviceKind.AFTER_THROWING,afterThrowingAnn.throwing()); } Around aroundAnn = method.getAnnotation(Around.class); if (aroundAnn != null) return new AdviceImpl(method,aroundAnn.value(),AdviceKind.AROUND); return null; } // 必须不是切面才行哦~~~~ public boolean isLocalClass() { return clazz.isLocalClass() && !isAspect(); } public boolean isMemberClass() { return clazz.isMemberClass() && !isAspect(); } // 内部类也是能作为切面哒 哈哈 public boolean isMemberAspect() { return clazz.isMemberClass() && isAspect(); } public String toString() { return getName(); } }
总结
工欲善其事必先利其器,任何负责的框架、业务也好。都是由一部分一部分的组件组合而成的。本文主旨就是单独把组件拆出来讲解,逐个击破~~