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部署
- 到eclipse官网下载http://www.eclipse.org/aspectj/downloads.php,直接用7zip解压或双击安装。
- 将aspectj1.x/lib/aspectjrt.jar拷贝到%JAVA_HOME%\jre\lib\ext中,注意这步很重要,否则会说找不到路径。
- 在IDE中设置Ajc编译器路径(编译器用于将aj文件编译成.class文件),以IDEA为例
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