天天看點

動态代理手動實作Spring AOP的基本功能

動态代理手動實作Spring AOP的基本功能:

這裡使用内部類實作, 實際上可能使用反射實作會更好一些, 沒仔細研究.

package com.frog.utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyUtils {
    private final Class<?> clazz;

    private Method method;

    public void setMethod(String methodName, Class<?>... parameterTypes) throws Exception {
        method = clazz.getMethod(methodName, parameterTypes);
    }

    public ProxyUtils(Class<?> clazz) {
        this.clazz = clazz;
    }

    public Object getProxy(){
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new TempClass());
    }

    private boolean isSameMethod(Method method1, Method method2){
        if(method1.getName().equals(method2.getName())){
            if (!method1.getReturnType().equals(method2.getReturnType()))
                return false;
            Class<?>[] params1 = method1.getParameterTypes();
            Class<?>[] params2 = method2.getParameterTypes();
            if (params1.length == params2.length) {
                for (int i = ; i < params1.length; i++) {
                    if (params1[i] != params2[i])
                        return false;
                }
                return true;
            }
        }
        return false;
    }

    private class TempClass implements InvocationHandler{
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
            if(ProxyUtils.this.method != null && !isSameMethod(ProxyUtils.this.method, method)) {
                return method.invoke(clazz.newInstance(), args);
            }
            Object result = null;
            boolean isNormal = true;
            try{
                ProceedingJoinPoint joinPoint = new ProceedingJoinPointImpl(method, args);
                if(around != null){
                    result = around.callBack(joinPoint);
                }else{
                    joinPoint.proceed();
                }
            }catch(Throwable t){
                isNormal = false;
                t.printStackTrace();
                return null;
            }finally{
                if(after != null) after.callBack();
                if(!isNormal && afterThrowing != null) afterThrowing.callBack();
            }

            if(afterReturning != null) afterReturning.callBack();
            return result;
        }

    }

    public interface ProceedingJoinPoint{
        public Object proceed() throws Throwable;
    }

    private class ProceedingJoinPointImpl implements ProceedingJoinPoint{
        private Method method;
        private Object[] args;
        public ProceedingJoinPointImpl(Method method, Object... args){
            this.method = method;
            this.args = args;
        }

        public Object proceed() throws Throwable{
            if(before != null) before.callBack();
            return method.invoke(clazz.newInstance(), args);
        }
    }

    private AroundHandler around;

    private AfterReturningHandler afterReturning;

    private AfterThrowingHandler afterThrowing;

    private BeforeHandler before;

    private AfterHandler after;

    public void setAroundAdvice(AroundHandler ah){
        around = ah;
    }

    public void setBeforeAdvice(BeforeHandler bmh){
        before = bmh;
    }

    public void setAfterThrowingAdvice(AfterThrowingHandler ath){
        afterThrowing = ath;
    }

    public void setAfterAdvice(AfterHandler amh){
        after = amh;
    }

    public void setAfterReturning(AfterReturningHandler arh){
        afterReturning = arh;
    }

    public interface AroundHandler{
        public abstract Object callBack(ProceedingJoinPoint joinPoint) throws Throwable;
    }

    public interface AfterReturningHandler{
        public abstract void callBack();
    }

    public interface AfterThrowingHandler{
        public abstract void callBack();
    }

    public interface BeforeHandler{
        public abstract void callBack();
    }

    public interface AfterHandler{
        public abstract void callBack();
    }
}