1. 业务代码
public interface CellPhone {
void description(Integer sequence);
void setVersion(String version);
}
public class IOS implements CellPhone {
private String version;
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public IOS(){}
public void description(Integer sequence) {
System.out.println("{sequence="+sequence+",version="+this.version+"}");
}
}
public class Android implements CellPhone {
private String version;
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public Android(){}
public void description(Integer sequence) {
System.out.println("{sequence="+sequence+",version="+this.version+"}");
}
}
1. 使用动态代理
实现代码:
public class CellPhoneProxy implements InvocationHandler{
private Object obj;
private CellPhoneProxy(Object obj){
this.obj = obj;
}
@SuppressWarnings("unchecked")
public static<T> T getProxyInstance(Class<T> clazz){
Object target = null;
try {
target = clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return (T)Proxy.newProxyInstance(clazz.getClassLoader(),
clazz.getInterfaces(), new CellPhoneProxy(target));
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if(method.getName().equals("description"))
System.out.print("call "+obj.getClass().getSimpleName()+"."+method.getName()+"():");
else
System.out.println("call "+obj.getClass().getSimpleName()+"."+method.getName()+"()");
Object result = method.invoke(obj, args);
return result;
}
}
测试代码:
public void test(){
/* Android */
CellPhone bean = CellPhoneProxy.getProxyInstance(Android.class);
bean.description(1);
bean.setVersion("4.2.0");
bean.description(2);
/* IOS */
bean = CellPhoneProxy.getProxyInstance(IOS.class);
bean.description(1);
bean.setVersion("7.2");
bean.description(2);
}
2. 使用cglib
实现代码:
public class CellPhoneInterceptor implements MethodInterceptor{
public Object intercept(Object target, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
if(method.getName().equals("description"))
System.out.print("call "+target.getClass().getSimpleName()+"."+method.getName()+"():");
else
System.out.println("call "+target.getClass().getSimpleName()+"."+method.getName()+"()");
Object rev = proxy.invokeSuper(target, args);
return rev;
}
}
测试代码:
public void test(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Android.class);
enhancer.setCallback(new CellPhoneInterceptor());
Android android = (Android)enhancer.create();
android.description(1);
android.setVersion("4.2.0");
android.description(2);
enhancer = new Enhancer();
enhancer.setSuperclass(IOS.class);
enhancer.setCallback(new CellPhoneInterceptor());
IOS ios = (IOS)enhancer.create();
ios.description(1);
ios.setVersion("7.2");
ios.description(2);
}
3. 使用javassit
实现代码:
public class CellPhoneTranslator implements Translator{
/**
* Class装载入JVM之前进行代码织入
*
*/
public void onLoad(ClassPool pool, String className) throws NotFoundException,
CannotCompileException {
CtClass cc = pool.get(className);
if(className.equals("edu.njupt.afly.aop.testclass.Android")){
//description方法织入
CtMethod description = cc.getDeclaredMethod("description");
description.insertBefore("{System.out.println(\"call Android description\");}");
//setVersion方法织入
CtMethod setVersion = cc.getDeclaredMethod("description");
setVersion.insertBefore("{System.out.println(\"call Android setVersion\");}");
}else if(className.equals("edu.njupt.afly.aop.testclass.IOS")){
//description方法织入
CtMethod description = cc.getDeclaredMethod("description");
description.insertBefore("{System.out.println(\"call IOS description\");}");
//setVersion方法织入
CtMethod setVersion = cc.getDeclaredMethod("description");
setVersion.insertBefore("{System.out.println(\"call IOS setVersion\");}");
}
}
public void start(ClassPool pool) throws NotFoundException,
CannotCompileException {
}
public static void main(String[] args) {
final CellPhone android = new Android();
final CellPhone mac = new IOS();
android.setVersion("4.2.0");
android.description(1);
mac.setVersion("7.2");
mac.description(2);
}
}
测试代码:
public void test(){
//获取存放CtClass的容器ClassPool
ClassPool cp = ClassPool.getDefault();
//创建一个类加载器
Loader cl = new Loader();
//增加一个转换器
try {
cl.addTranslator(cp, new CellPhoneTranslator());
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
}
try {
cl.run("edu.njupt.afly.aop.javassist.CellPhoneTranslator", null);
} catch (Throwable e) {
e.printStackTrace();
}
}
4. 总结
- 实现方式:动态代理使用java的反射机制,通过在运行期生成接口的代理子类来实现;cglib是利用字节码技术,在运行期实现一个目标类的子类,然后在子类中通过拦截的方式织入横切逻辑,其实现依赖于ASM;javassist也是利用字节码技术,但是javassit是在类加载阶段将横切逻辑织入进方法体内,所以其效率更好。
- 特点:发射和cglib是在运行期实现横切逻辑的织入,所以其效率较低,但是胜在可以获得方法调用的参数和返回值,功能更强大;而javassist因为是在类加载阶段织入横切逻辑,所以其效率相较于前两种方式较高,但是无法获得调用参数和返回值,有局限性。
以上是个人理解,欢迎大家批评指正。