点 线 面
AOP(Aspect Oriented Programming) 面向方面的编程
基本概念
- Target: 目标,目标类
 
- Aspect: 跨越多个类的功能层面,比如事务管理、日志管理等等
 
- Pointcut: 切点,筛选出目标方法,关联一个表达式,即哪些方法是代理范围
 
- Joinpoint: 连接点,程序执行时间点,比如方法执行时、异常处理时等等
 
- Advice:增强逻辑,要额外执行的动作
- Before: 时间点前执行,不能阻止时间点执行
 
- After returning: 时间点无异常完成后执行
 
- After throwing: 异常后执行
 
- After(Finally): 时间点后执行,不管有无异常
 
- Around: 之前之后都处理,最通用最强大的类型
 
 
- Weaving: 将增强逻辑引入目标
- 编译时,需要特殊编译器,可以添加源码再编译,也可以编译后针对class文件直接把二进制字节码插入
 
- 加载时,需要特殊类加载器,加载时添加额外逻辑
 
- 运行时, 构建动态代理,针对已经加载到JVM的类
 
 
- Introduction: 给被代理对象增加额外的方法或属性
 
静态代理
手动编写维护代理类,代理类和目标实现同一接口
- 每个需要代理的类都需要手动自己进行代理实现,数量多的话需要创建大量代理类文件
 
- 代理类实现接口,方法多很繁杂并且代码机械重复,而且接口变化如添加方法,代理类也要同步修改
 
动态代理可以动态生成代理类,无需手动编写,只需要专注于处理逻辑
JDK 动态代理
运行时生成具备一组接口的新类,该类继承了java.lang.reflect.Proxy,由于不能多继承,因此要求必须有接口才行
代理类在调用具体方法时交给handler处理
要求
- 目标对象必须实现了接口
 
- 需要InvocationHandler内部维护目标对象
 
生成代理所需参数:目标类的加载器,目标接口数组,处理器
Sample1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   |  class UppercaseValueHandler implements InvocationHandler {     Object target;
      public UppercaseValueHandler(Object obj) {         target = obj;     }
      @Override     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {         if (method.getName().equals("put")) {             String value = String.valueOf(args[1]);             args[1] = value.toUpperCase();         }         return method.invoke(target, args);     } }
  public class Test {     public static void main(String[] args) throws IOException {         Map<String, String> target = new HashMap<>();         Map<String, String> proxy = (Map<String, String>)Proxy.newProxyInstance(                 Map.class.getClassLoader(), new Class[] { Map.class }, new UppercaseValueHandler(target));         proxy.put("foo", "bar");         System.out.println(proxy.getClass().getName());          System.out.println(target);      } }
 
  | 
 
CGLIB 动态代理
CGLIB字节码修改,继承生成子类,重写覆盖方法
Sample1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   |  class UppercaseValueInterceptor implements MethodInterceptor {     @Override     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {         if (method.getName().equals("put")) {             String value = String.valueOf(args[1]);             args[1] = value.toUpperCase();         }         return proxy.invokeSuper(obj, args);     } }
  public class Test {     public static void main(String[] args) {         Enhancer enhancer = new Enhancer();         enhancer.setSuperclass(HashMap.class);         enhancer.setCallback(new UppercaseValueInterceptor());
          Map<String,String> proxy = (Map<String, String>) enhancer.create();         proxy.put("foo", "bar");         System.out.println(proxy.getClass().getName());          System.out.println(proxy);      } }
 
  | 
 
注意点
动态代理也会把Object类的hashCode,equals,toString进行代理实现,其他Object方法不会代理作用于代理对象本身
所以代理对象和真实对象是equal的,hashCode和toString也相同
对比
JDK执行性能差,但是创建时间短,需要有接口
CGLIB执行性能好,但是创建时间长,需要能继承子类
只创建一次代理的情况下,比如单例,优先使用CGLIB
应用
- 执行时间统计
 
- Mock框架
 
- ORM框架
 
- IOC容器
 
- 诊断工具
 
- 代码生成