码迷,mamicode.com
首页 > 其他好文 > 详细

AOP切面编程

时间:2015-07-14 13:52:53      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:

AOP的实现底层实际上即为反射,JDK中的反射类java.lang.reflect.Proxy是Java中唯一可以访问调度器的类。类似地,常见的动态代理库cglib也是通过反射机制实现了动态代理的封装。技术成熟度相对较高的AspectJ和Spring AOP会在底层实现一套reflect机制,区别是两者对规范实现如何定义而已。

无论是AspectJ还是Spring AOP,所有这些AOP编程都是基于反射和运行时的动态代理控制实现的。下面通过Proxy和Cglib来实现自己的动态代理切面。

假设我要实现一套基于注解的Trasaction事务管理,通过AOP动态代理来实现。注解和接口实现如下

/**
 * @author Barudisshu
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface TransactionAnn {
    String[] name() default {};

    boolean[] readonly() default false;

    int[] level() default Connection.TRANSACTION_READ_COMMITTED;

    String value() default "";
}
/**
 * @author Barudisshu
 */
public interface Transaction {
    void open();
    void rollBack();
    void commit();
    void closeIfStillOpen();
}

Proxy动态代理

动态代理的机制如下

技术分享

实现一个代理工厂

/**
 * 代理工厂类
 * @author Barudisshu
 */
public class AspectFactory {
    /**单例实现*/
    private AspectFactory(){

    }
    @SuppressWarnings("unchecked")
    public static <T> T getInstance(T target,Aspect... aspects){
        AspectHandler handler = new AspectHandler(target, aspects);
        Class clazz = target.getClass();
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), clazz.getInterfaces(), handler);

    }
}

封装并继承调度器

/**
 * @author Barudisshu
 */
public class AspectHandler implements InvocationHandler {

  private Object target = null;
  private Aspect[] aspects = null;
  private int index = -1;

  public AspectHandler(int index, Object target, Aspect[] aspects) {
    this.index = index;
    this.target = target;
    this.aspects = aspects;
  }

  public AspectHandler(Object target, Aspect[] aspects) {
    this.target = target;
    this.aspects = aspects;
  }


  public Object getTarget() {
    return target;
  }


  public void setTarget(Object target) {
    this.target = target;
  }

  public Aspect[] getAspects() {
    return aspects;
  }


  public void setAspects(Aspect... aspects) {
    this.aspects = aspects;
  }

  /**
   * 委托方法
   *
   * @param proxy  代理对象
   * @param method 代理方法
   * @param args   方法参数
   */
  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
    if (index == -1) {
      return new AspectHandler(0, target, aspects).invoke(proxy, method, args);
    }
    Object result = null;
    if (index < aspects.length) {
      result = aspects[index++].aspect(this, proxy, method, args);
    } else if (index++ == aspects.length) {
      result = method.invoke(target, args);
    }
    return result;
  }

}
/**
 * @author Barudisshu
 */
public interface Aspect {

  public Object aspect(InvocationHandler ih, Object proxy, Method method, Object[] args) throws Throwable;

}
实现真实对象,真实对象继承Aspect,并将通过AspectHandler被委托代理
/**
 * @author Barudisshu
 */
public class TransactionAspect implements Aspect {

    public Object aspect(InvocationHandler ih, Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;

        TransactionAnn transactionAnn = method.getAnnotation(TransactionAnn.class);
        if (transactionAnn != null) {
            Transaction transaction = new TransactionAdapter();

            // TODO: 获取注解信息或设置值
            String[] names = transactionAnn.name();
            String values = transactionAnn.value();
            int[] level = transactionAnn.level();
            boolean[] readOnly = transactionAnn.readonly();

            try {

                //执行操作
                result = ih.invoke(proxy, method, args);

                // TODO: 处理
                transaction.open();
                transaction.commit();
            }catch (Throwable t) {

                // if exception
                transaction.rollBack();

                Throwable cause = t.getCause();
                if (cause != null) {
                    // you should define your own Exception here
                    throw new TransactionException(cause.getMessage(), cause);
                } else {
                    throw new TransactionException(t.getMessage(), t);
                }

            }finally {
                // finally
                transaction.closeIfStillOpen();
            }
        } else {
            //执行操作
            result = ih.invoke(proxy, method, args);
        }
        return result;
    }
}

根据时序图,我们接下来只需要创建相应的客户端进行调度即可

/**
 * @author Barudisshu
 */
public class AspectClient {

    public static void main(String[] args) {

        PersistenceService persistenceService = AspectFactory.getInstance(new PersistenceServiceImpl(), new TransactionAspect());

        persistenceService.save(3,"321");
    }
}
/**
 * @author Barudisshu
 */
public interface PersistenceService {

    @TransactionAnn(name = "save")
    void save(long id,String data);

    @TransactionAnn(level = Connection.TRANSACTION_READ_UNCOMMITTED)
    String load(long id);
}
/**
 * @author Barudisshu
 */
public class PersistenceServiceImpl implements PersistenceService {

    @Override
    public void save(long id, String data) {
        throw new TransactionException("异常则回滚!!!");
    }

    @Override
    public String load(long id) {
        return null;
    }
}
在这里,我们显示抛出一个 运行时异常TranscationException,运行客户端将执行transaction.rollBack()方法。

既然有JDK的Proxy代理了,为什么还需要使用CGLIB之类的其他外部库?实际上Proxy只是对代理的简单实现,在实际使用中还不能满足需求,如上述设计中,Proxy的newProxyInstance静态方法是通过clone实现的,可能需要考虑是浅拷贝还是深拷贝的问题。

若以CGLIB实现,则问题会显得简单的多。

CGLIB动态代理

创建单例的代理工厂

public class CGLIBProxyFactory {

    private CGLIBProxyFactory() {
    }

    @SuppressWarnings("unchecked")
    public static <T> T createProxy(T target, AOPInterceptor interceptor) {

        MethodInterceptor methodInterceptor = 
            new CGLIBMethodInterceptor(interceptor);

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setInterfaces(target.getClass().getInterfaces());
        enhancer.setCallback(methodInterceptor);
        return (T) enhancer.create();
    }
}

在Cglib则是通过方法拦截器直接实现,只需要继承拦截器即可

/**
 * @author Barudisshu
 */
public class CGLIBMethodInterceptor implements MethodInterceptor {

    private AOPInterceptor interceptor;

    public CGLIBMethodInterceptor(AOPInterceptor interceptor) {
        this.interceptor = interceptor;
    }

    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        try {
            interceptor.before(method, args);
            Object returnValue = methodProxy.invokeSuper(object, args);
            interceptor.after(method, args);
            return returnValue;
        } catch (Throwable t) {
            interceptor.afterThrowing(method, args, t);
            throw t;
        } finally {
            interceptor.afterFinally(method, args);
        }
    }
}
/**
 * @author Barudisshu
 */
public interface AOPInterceptor {

    void before(Method method, Object[] args);
    void after(Method method, Object[] args);
    void afterThrowing(Method method, Object[] args, Throwable throwable);
    void afterFinally(Method method, Object[] args);
}
添加事务处理的真实对象
/**
 * @author Barudisshu
 */
public class TransactionCglib implements AOPInterceptor {

    private Transaction transaction;

    @Override
    public void before(Method method, Object[] args) {
        if (isRequiresNew(method)) {
            transaction = new TransactionAdapter();
            transaction.open();
        }
    }

    @Override
    public void after(Method method, Object[] args) {
        if (transaction != null) {
            transaction.commit();
        }
    }

    @Override
    public void afterThrowing(Method method, Object[] args, Throwable throwable) {
        if (transaction != null) {
            transaction.rollBack();
        }
    }

    @Override
    public void afterFinally(Method method, Object[] args) {
        if (transaction != null) {
            transaction.closeIfStillOpen();
            transaction = null;
        }
    }

    protected boolean isRequiresNew(Method method) {
        TransactionAnn transactionAnnotation = method.getAnnotation(TransactionAnn.class);

        if (transactionAnnotation != null) {
            if ("REQUIRES_NEW".equals(transactionAnnotation.value())) {
                return true;
            }
        }

        return false;
    }
}

OK,十分简单,Transaction真实对象将被MethodInterceptor封装,并在Enhancer中实现回调。下面只需要添加相应的客户端调用即可

/**
 * @author Barudisshu
 */
public class CglibClient {

    public static void main(String[] args) {
        PersistenceService persistenceService = CGLIBProxyFactory.createProxy(new PersistenceServiceImpl(), new TransactionCglib());

        persistenceService.save(3L, "321");
    }
}

注意和Proxy中实现的不同

/**
 * @author Barudisshu
 */
public class PersistenceServiceImpl implements PersistenceService {

    @TransactionAnn("REQUIRES_NEW")
    public void save(long id, String data) {
        System.out.println("Generally save ... ");
    }

    @TransactionAnn("NOT_SUPPORTED")
    public String load(long id) {
        return null;
    }
}

鉴于AspectJ和Spring AOP切面内容比较多,下面简单讲一下AspectJ的配置。

AspectJ部署

  1. 到eclipse官网下载http://www.eclipse.org/aspectj/downloads.php,直接用7zip解压或双击安装。
  2. 将aspectj1.x/lib/aspectjrt.jar拷贝到%JAVA_HOME%\jre\lib\ext中,注意这步很重要,否则会说找不到路径。
  3. 在IDE中设置Ajc编译器路径(编译器用于将aj文件编译成.class文件),以IDEA为例
技术分享
编译器一定是aspectjtools,不要选错。

OK,差不多了,写个测试例子

/**
 * @author Barudisshu
 */
public aspect HelloWorld {

    pointcut callPointcut():
        call(void cn.barudisshu.aop.MyClass.foo(int,java.lang.String));

    before():callPointcut(){
        System.out.println("Hello World");
        System.out.println("In the advice attached to the call pointcut");
    }
    after():callPointcut(){
        System.out.println("All things has done");
    }
}

方法切入点

/**
 * @author Barudisshu
 */
public class MyClass {

    public void foo(int number,String name){
        System.out.println("Inside foo (int,String)");
    }

    public static void main(String[] args) {
        // Create an instance of MyClass
        MyClass myObject = new MyClass();
        // Make the call to foo
        myObject.foo(1,"Russ Miles");
    }
}

如下代码将输出

Hello World
In the advice attached to the call pointcut
Inside foo (int,String)
All things has done

AOP切面编程

标签:

原文地址:http://my.oschina.net/Barudisshu/blog/478316

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!