自分でspring-AOPの構想を実現します.

6466 ワード

aopのローディング順序は、IOCローディングの前、すなわちプロキシクラスのインスタンスが完了した後に、このインスタンスに属性を注入する必要がある.
 注釈ベースのaopを実現します.
  1、切断面を定義してAsppectを注釈する
/**
 *     
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Aspect {

    Class extends Annotation>  value();
}
  2、代理インターフェースProxyを定義し、このインターフェースを実現する抽象類を定義します.  AsppectProxy)
/**
 *     
 */
public interface Proxy {
    /**
     *       
     * @param proxyChain
     * @return
     * @throws Throwable
     */
    Object doProxy(ProxyChain proxyChain) throws Throwable;
}
/**
 *     
 */
public abstract class AspectProxy implements Proxy {

    private static final Logger logger = LoggerFactory.getLogger(AspectProxy.class);

    @Override
    public final Object doProxy(ProxyChain proxyChain) throws Throwable {
        Object result = null;

        Class> cls = proxyChain.getTargetClass();
        Method method = proxyChain.getTargetMethod();
        Object[] params = proxyChain.getMethodParams();

        begin();
        try {
            if (intercept(cls, method, params)) {
               boolean flag = before(cls, method, params);
                if(!flag){
                   return "...";
                }
                  result = proxyChain.doProxyChain();
                after(cls, method, params, result);
            } else {
                result = proxyChain.doProxyChain();
            }
        } catch (Exception e) {
            logger.error("proxy failure", e);
            error(cls, method, params, e);
            throw e;
        } finally {
            end();
        }

        return result;
    }

    public void begin() {
    }

    public boolean intercept(Class> cls, Method method, Object[] params) throws Throwable {
        return true;
    }

    public boolean before(Class> cls, Method method, Object[] params) throws Throwable {
        return true;
    }

    public boolean after(Class> cls, Method method, Object[] params, Object result) throws Throwable {
        return true;
    }

    public void error(Class> cls, Method method, Object[] params, Throwable e) {
    }

    public void end() {
    }
}
 3、代理チェーンProxyChinを定義する
/**
 *    
 *
 */
public class ProxyChain {

    private final Class> targetClass;//   
    private final Object targetObject;//    
    private final Method targetMethod;//    
    private final MethodProxy methodProxy;//    
    private final Object[] methodParams;//    

    private List proxyList = new ArrayList();//    
    private int proxyIndex = 0;//    

    public ProxyChain(Class> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List proxyList) {
        this.targetClass = targetClass;
        this.targetObject = targetObject;
        this.targetMethod = targetMethod;
        this.methodProxy = methodProxy;
        this.methodParams = methodParams;
        this.proxyList = proxyList;
    }

    public Object[] getMethodParams() {
        return methodParams;
    }

    public Class> getTargetClass() {
        return targetClass;
    }

    public Method getTargetMethod() {
        return targetMethod;
    }

    public Object doProxyChain() throws Throwable {
        Object methodResult;
        if (proxyIndex < proxyList.size()) {//        
            methodResult = proxyList.get(proxyIndex++).doProxy(this);//       ,        
        } else {//    ,           
            methodResult = methodProxy.invokeSuper(targetObject, methodParams);
        }
        return methodResult;
    }
}
 4、プロキシマネージャProxyManagerを定義します.このクラスはプロジェクト起動時に呼び出され、目標クラスを具体化します.
  
 *      
 *
 */
public class ProxyManager {

    @SuppressWarnings("unchecked")
    public static  T createProxy(final Class> targetClass, final List proxyList) {
        return (T) Enhancer.create(targetClass, new MethodInterceptor() {
            @Override
            public Object intercept(Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable {
                return new ProxyChain(targetClass, targetObject, targetMethod, methodProxy, methodParams, proxyList).doProxyChain();//            
            }
        });
    }
}
5、AOPAHelperは、プロジェクトの起動時に、プロキシを生成するクラスを取得し、ProxyManagerを呼び出し、これらのクラスを実際化して保存したインスタンスをbeansに保存し、その後のアクセス呼び出しはaop機能を持つ.
  
static {
    try {
        Map, Set>> proxyMap = createProxyMap();//  AspectProxy   ,     Aspect  ,       ,         ,                     (        aop   )
        Map, List> targetMap = createTargetMap(proxyMap);//                    
        for (Map.Entry, List> targetEntry : targetMap.entrySet()) {//           
            Class> targetClass = targetEntry.getKey();
            List proxyList = targetEntry.getValue();
            System.out.println("targetClass:"+targetClass.getName());
            System.out.println("proxyList:"+proxyList.get(0).toString());
            Object proxy = ProxyManager.createProxy(targetClass, proxyList);//   
            BeanHelper.setBean(targetClass, proxy);//            Beans 

        }
    } catch (Exception e) {
        LOGGER.error("aop failure", e);
    }
}
----------------------------ここに、簡単なaopの開発が完了する-------------------------------------------------------------
呼び出し:
   
/**
 *    Controller     ,         ,    ,      
 */
@Aspect(Controller.class)
public class ControllerAspect extends AspectProxy {

    private static final Logger LOGGER = LoggerFactory.getLogger(ControllerAspect.class);

    private long begin;

    @Override
    public boolean before(Class> cls, Method method, Object[] params) throws Throwable {
        LOGGER.debug("---------- begin ControllerAspect ----------");

        if(true){
            return true;
        }
        return false;
    }

    @Override
    public boolean after(Class> cls, Method method, Object[] params, Object result) throws Throwable {

        LOGGER.debug("----------- end ControllerAspect-----------");
        if(true){
            return true;
        }
        return false;
    }
}