0
点赞
收藏
分享

微信扫一扫

面试官:你实现过 AOP 吗?AOP的简单实现,现在奉上

小磊z 2022-05-04 阅读 65
javaspring

手写 AOP

1.0实现

  1. 基于 CGLib实现动态代理

  2. 实现 @Aspect、@Order 注解

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Aspect {
        // 表示当前被 Aspect 标记的横切逻辑,会织入到被属性逻辑标记的那些类中
        Class<? extends Annotation> value();
    }
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Order {
        // 规定value越小优先级越高
        int value();
    }
    
  3. 实现 DefaultAspect 所有切面必须继承 DefaultAspect

    public abstract class DefaultAspect {
        /**
         * 前置拦截
         * @param targetClass 被代理的目标类
         * @param method 被代理的目标方法
         * @param args 被代理的目标方法对应的参数列表
         * @throws Throwable
         */
        public void before(Class<?> targetClass, Method method,Object[] args) throws Throwable{
    
        }
    
        /**
         *
         * @param targetClass 被代理的目标类
         * @param method 被代理的目标方法
         * @param args 被代理的目标方法对应的参数列表
         * @param returnValue 被代理的目标方法执行后的返回值
         * @return
         * @throws Throwable
         */
        public Object afterReturning(Class<?> targetClass, Method method,Object[] args,Object returnValue)throws Throwable{
            return returnValue;
        }
    
        /**
         *
         * @param targetClass 被代理的目标类
         * @param method 被代理的目标方法
         * @param args 被代理的目标方法对应的参数列表
         * @param e 被代理的目标方法抛出异常
         * @throws Throwable
         */
        public void afterThrowing(Class<?> targetClass, Method method,Object[] args,Throwable e) throws Throwable{
    
        }
    }
    
    
  4. Aspect的排序以及Advice的定序执行

    public class AspectInfo {
        private int orderIndex;
        private DefaultAspect aspectObject;
    }
    

    将 @Order 的值与 Aspect 的实现放入 List<AspectInfo>中,并将其按照 @Order 的值进行排序,以实现 Advice 的定序执行

  5. 横切逻辑的织入

    通过 CGLib 实现横切逻辑的织入

        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            Object returnValue = null;
            // 1. 按照order的顺序升序执行完所有Aspect的before方法
            invokeBeforeAdvices(method, args);
            try {
                // 2. 执行被代理类的方法
                returnValue = methodProxy.invokeSuper(proxy, args);
                // 3. 如果被代理方法正常返回,则按照order的顺序降序执行完所有的 Aspect 的afterReturning方法
                returnValue = invokeAfterReturningAdvices(method, args, returnValue);
            } catch (Exception e) {
                // 4. 如果被代理方法抛出异常,则按照order的顺序降序执行完所有 Aspect 的afterThrowing方法
                invokeAfterThrowingAdives(method, args, e);
            }
            return returnValue;
        }
    

1.0的短板

Pointcut 粒度只能支持到注解级别,即只能筛选出被诸如 @Controller @Service 等注解标记的类的集合进行横切逻辑的织入

2.0 引入 AspectJ 的表达式解析功能

    /**
     * 表达式解析器
     */
    private PointcutExpression pointcutExpression;

    public PointcutLocator(String expression) {
        this.pointcutExpression = pointcutParser.parsePointcutExpression(expression);
    }

    /**
     * 判断传入的Class对象是否是Aspect的目标代理类,即匹配的Pointcut表达式(初筛)
     *
     * @param targetClass 表达式
     * @return 是否匹配
     */
    public boolean roughMatches(Class<?> targetClass) {
        // 只能校验within
        // 不能校验(execution,call,get,set),面对无法校验的表达式,直接返回true
        return pointcutExpression.couldMatchJoinPointsInType(targetClass);
    }

    /**
     * 判断传入的 Method 对象是否是Aspect的目标代理方法,即匹配 Pointcut表达式(精筛)
     * @param method
     * @return
     */
    public boolean accurateMatches(Method method) {
        ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
        return shadowMatch.alwaysMatches();
    }

相应的对1.0 进行修改

  1. 修改 @Aspect 注解

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Aspect {
        // 表示当前被 Aspect 标记的横切逻辑,被织入类的位置
        String pointcut();
    }
    
  2. 修改对应的 AspectInfo

    public class AspectInfo {
    	// 优先级
        private int orderIndex;
        // Aspect实例
        private DefaultAspect aspectObject;
        // 依据 @Aspect 的值。为其注入对应的 PointcutExpression
        private PointcutLocator pointcutLocator;
    }
    

源码在这!!

https://github.com/zunchang/simpleframework

举报

相关推荐

0 条评论