代理在java语言中应用非常广泛,一个对象的功能借助另一个有相同功能的对象来完成,功能业务逻辑不变,这样可以添加一些额外的“轻逻辑”进去

这里的轻逻辑是指一些通用逻辑,比如在一个代理方法调用之前之后加一些日志,或者在执行数据库操作之前之后做一些事务处理

java代理分为两种:静态代理和动态代理,静态代理就是在编译成字节码之前代理就已经发生了,动态代理就是字节码加载到内存的时候,根据是否需要再代理

首先我们定义一个接口:

package com.framework.common.java.delegate;  
/**  
 * 定义车的功能  
 */  
public interface ICar {  
  /**  
   * 车可以行驶  
   */  
  void drive();  
}


再定义一些“轻逻辑”的小功能

package com.framework.common.java.delegate;  
/**  
 * 横切逻辑,一般用作代码通用逻辑  
 */  
public class Navigator {  
  public static void start(){  
    System.out.println("开始导航 ... ");  
  }  
  public static void end(){  
    System.out.println("结束导航 ... ");  
  }  
}


做一个静态代理:

package com.framework.common.java.delegate;  
/**  
 * 被代理方  
 */  
class BaoMa implements ICar{  
  public void drive() {  
    System.out.println("宝马车开始行驶 ... ");  
  }  
}
/**  
 * 代理方  
 */  
class Car1 implements ICar{  
  private ICar delegate;  
  public Car1(ICar delegate){  
    this.delegate = delegate;  
  }  
  public void drive() {  
    Navigator.start();  
    delegate.drive();  
    Navigator.end();  
  }  
}
/**
 * 静态代理
 */
public class MyDelegate {
  public static void main(String[] args){
    ICar car = new Car1(new BaoMa());
    car.drive();
  }
}


结果为:


开始导航 ...   
宝马车开始行驶 ...   
结束导航 ...

静态代理中,我们代理类和被代理类的代码都得自己写,而且一般至少要写两个类,而且在编写的时候,我们就要知道代理逻辑,并把代码逻辑编码到每个代理类中


幸好我们有动态代理技术,动态代理正好解决了这个问题,我们只需要编写一份代理逻辑,就可以动态代理一批类


动态代理有三种方式jdk动态代理,asm动态代理,cglib动态代理(实际来讲只有两种,cglib只是封装了前两种代理方式,但是用法上我们可以把它们当作三种)

jdk动态代理:

package com.framework.common.java.delegate;  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  
/**
* 需要被切面的对象  
 */  
class BenChi implements ICar {  
  public void drive() {  
    System.out.println("奔驰车开始行驶 ... ");  
  }  
}



/**
 * jdk横向动态代理
 */
public class JdkAspect {
  /**
   * jdk 的横切编程
   */
  public static void main(String[] args) {
    ICar car = (ICar) new Weaver().newInstance(new BenChi());
    car.drive();
  }
}
/**
 * 织入构造器
 */
class Weaver implements InvocationHandler {
  private Object target;
  public Object newInstance(Object target) {
    this.target = target;
    Class<?> clasz = target.getClass();
    return Proxy.newProxyInstance(clasz.getClassLoader(), clasz.getInterfaces(), this);
  }
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Navigator.start();
    Object result = method.invoke(target, args); 
    Navigator.start();
    return result;
  }
}


结果为:

开始导航 ...   
奔驰车开始行驶 ...   
开始导航 ...

asm动态代理,asm是动态字节码技术,它操作java字节码文件,并动态定义各个方法指令,通过这种方式在代码中嵌入横向逻辑

asm代理需要引入asm相关的依赖这里面我引入的是spring自己集成的asm,其中用法跟asm原生的包是一样的:spring-asm-3.1.0.RELEASE.jar

package com.framework.common.java.delegate;  
import org.springframework.asm.ClassAdapter;  
import org.springframework.asm.ClassReader;  
import org.springframework.asm.ClassVisitor;  
import org.springframework.asm.ClassWriter;  
import org.springframework.asm.MethodAdapter;  
import org.springframework.asm.MethodVisitor;  
import org.springframework.asm.Opcodes;  
  
import java.lang.reflect.Method;  
/**  
 * 业务类  
 */  
class AoDi {  
  public void myDrive() {  
    System.out.println("奥迪车开始行驶 ... ");  
  }  
}  
/**  
 * asm动态代理  
 */  
public class AsmAspect {  
  public static void main(String[] args) throws Exception {  
    AoDi audi = (AoDi) new ClassTransformer().newInstance(AoDi.class);  
    audi.myDrive();  
  }  
}  
/**  
 * class解析  
 */  
class ClassModifier extends ClassAdapter implements Opcodes {  
  private String adviceName = Navigator.class.getName().replace(".", "/");  
  private String className;  
  private String superName;  
  public ClassModifier(ClassVisitor cv, String className, String superName) {  
    super(cv);  
    this.className = className.replace(".", "/");  
    this.superName = superName.replace(".", "/");  
  }  
  @Override  
  public void visit(int version, int access, String name, String signature, String objectName,  
      String[] interfaces) {  
    super.visit(version, ACC_PUBLIC, className, signature, superName, interfaces);  
  }  
  @Override  
  public MethodVisitor visitMethod(int access, String name, String desc, String signature,  
      String[] exceptions) {  
    MethodModifier method =  
        new MethodModifier(super.visitMethod(access, name, desc, signature, exceptions), name);  
    if (name.equals("<init>")) {  
      method.visitCode();  
      method.visitVarInsn(ALOAD, 0);  
      method.visitMethodInsn(INVOKESPECIAL, superName, "<init>", "()V");  
      method.visitInsn(RETURN);  
      method.visitMaxs(1, 1);  
      method.visitEnd();  
    }  
    return method;  
  }  
  
  /**  
   * method 解析  
   */  
  class MethodModifier extends MethodAdapter implements Opcodes {  
    private String methodName;  
    public MethodModifier(MethodVisitor arg0, String methodName) {  
      super(arg0);  
      this.methodName = methodName;  
    }  
    @Override  
    public void visitCode() {  
      if (!methodName.equals("<init>")) {  
        mv.visitMethodInsn(INVOKESTATIC, adviceName, "start", "()V");//织入逻辑  
      }  
    }  
    public void visitInsn(int opcode) {  
      if (!methodName.equals("<init>")) {  
        if ((opcode >= IRETURN && opcode <= RETURN) || opcode == ATHROW) {  
          mv.visitMethodInsn(INVOKESTATIC, adviceName, "end", "()V");//织入逻辑  
        }  
      }  
      mv.visitInsn(opcode);  
    }  
  }  
}  
/**  
 * 子类生成  
 */  
class ClassTransformer {  
  private Class<?> modifyClass(Class<?> targetClass) throws Exception {  
    String superName = targetClass.getName();  
    String className = superName + "$asmProxy";  
    ClassLoader loader = targetClass.getClassLoader();  
    Method getClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);  
    getClass.setAccessible(true);  
    Class<?> clasz = (Class<?>) getClass.invoke(loader, className);  
    if (clasz == null) {  
      ClassWriter classWriter = new ClassWriter(true);  
      new ClassReader(targetClass.getResourceAsStream(targetClass.getSimpleName() + ".class")).accept(new ClassModifier(classWriter, className, targetClass.getName()), true);  
      byte[] bytes = classWriter.toByteArray();  
      Method load = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);  
      load.setAccessible(true);  
      clasz = (Class<?>) load.invoke(loader, className, bytes, 0, bytes.length);//classloader加载重定义的字节码文件  
    }  
    return clasz;  
  }  
  public Object newInstance(Class<?> targetClass) throws Exception {  
    Class<?> clasz = modifyClass(targetClass);  
    return clasz.newInstance();  
  }  
}



运行结果为:

开始导航 ...   
奥迪车开始行驶 ...   
结束导航 ...


cglib的代理封装了jdk和asm的逻辑,因此其代码看起来比asm要整洁得多,cglib代理需要引入cglib依赖,如:cglib-nodep-3.1.jar依赖


package com.framework.common.java.delegate;  
import net.sf.cglib.proxy.Enhancer;  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  
/**  
 * 业务类  
 */  
class LuHu {  
  public void myDrive(){  
    System.out.println("路虎车开始行驶 ... ");  
  }  
}  
/**  
 * cglib动态代理  
 */  
public class CglibAspect {  
  public static void main(String[] args) {  
    Enhancer enhancer = new Enhancer();  
    enhancer.setSuperclass(LuHu.class);  
    enhancer.setCallback(new MethodInterceptorImpl());  
    LuHu car = (LuHu) enhancer.create();  
    car.myDrive();  
  }  
}  
/**  
 * 方法适配器  
 */  
class MethodInterceptorImpl implements MethodInterceptor {  
  public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,  
      MethodProxy proxy) throws Throwable {  
    Navigator.start();  
    Object result = proxy.invokeSuper(obj, args);  
    Navigator.end();  
    return result;  
  }  
}


运行结果为:

开始导航 ...   
路虎车开始行驶 ...   
结束导航 ...


可以看出,借助代理,我们可以把程序业务逻辑和横向通用逻辑分开,把代码进行解耦,让代码编写人员可以分别关注不同的模块,让架构设计更灵活。