zoukankan      html  css  js  c++  java
  • 利用Cglib实现AOP

    前文讲了, 可以利用Spring, Guice等框架提供的容器实现AOP, 如果想绕过容器, 直接注入Class,

    可以利用Cglib为对象加上动态代理,实现代码切入, 但是每次调用比较繁琐,

    因此我们还需要给他加了一层语法糖, 使之更易用.

    Advice

    Spring带了一堆Advice, 我们只模拟实现环绕Advice, 以及增加了一个Clear切入的注解, 下面看具体实现.

     1 /**
     2  * 环绕Advie
     3  *
     4  * 可以加在类上, 或者方法上.
     5  * 加在类上的话, 类中所有无@Clear注解的方法都会被切入
     6  *
     7  *     @Before({CustomInterceptor.class, B.class})
     8  *     @Before(CustomInterceptor.class)
     9  */
    10 @Inherited
    11 @Retention(RetentionPolicy.RUNTIME)
    12 @Target({ElementType.TYPE, ElementType.METHOD})
    13 public @interface Before {
    14     Class<? extends Interceptor>[] value();
    15 }
     1 /**
     2  * 清除Advice
     3  *
     4  * 可以清除方法上的指定Interceptor, 若不指定, 则清除所有切入.
     5  *
     6  *     @Clear 清除所有
     7  *     @Clear(CustomInterceptor.class) 清除CustomInterceptor
     8  */
     9 @Inherited
    10 @Retention(RetentionPolicy.RUNTIME)
    11 @Target({ElementType.TYPE, ElementType.METHOD})
    12 public @interface Clear {
    13     Class<? extends Interceptor>[] value() default {};
    14 }

    语法糖

    直接调用Cglib做切入, 需要setSuperClass, setCallback等等.

    1   Enhancer enhancer = new Enhancer();
    2   enhancer.setSuperclass(AopDemo.class);
    3   enhancer.setCallback(new MethodInterceptorImpl());
    4  
    5   AopDemo demo = (AopDemo) enhancer.create();

    我们需要对Enhancer以及Callback进行封装, 减少复杂度

      1 import java.util.concurrent.ConcurrentHashMap;
      2 
      3 /**
      4  * cglib中Enhancer的语法糖, 让注入更简单点
      5  */
      6 public class Enhancer {
      7     
      8     private static final ConcurrentHashMap<String, Object> singleton = new ConcurrentHashMap<String, Object>();
      9     
     10     private Enhancer(){}
     11 
     12     public static <T> T enhance(Class<T> targetClass) {
     13         return (T)net.sf.cglib.proxy.Enhancer.create(targetClass, new Callback());
     14     }
     15     
     16     public static <T> T enhance(Class<T> targetClass, Interceptor... injectInters) {
     17         return (T)net.sf.cglib.proxy.Enhancer.create(targetClass, new Callback(injectInters));
     18     }
     19 
     20     public static <T> T getTarget(String singletonKey) {
     21         return (T)singleton.get(singletonKey);
     22     }
     23     
     24     public static <T> T enhance(String singletonKey, Class<T> targetClass) {
     25         Object target = singleton.get(singletonKey);
     26         if (target == null) {
     27             target = enhance(targetClass);
     28             singleton.put(singletonKey, target);
     29         }
     30         return (T)target;
     31     }
     32     
     33     public static <T> T enhance(String singletonKey, Class<T> targetClass, Interceptor... injectInters) {
     34         Object target = singleton.get(singletonKey);
     35         if (target == null) {
     36             target = enhance(targetClass, injectInters);
     37             singleton.put(singletonKey, target);
     38         }
     39         return (T)target;
     40     }
     41     public static <T> T enhance(Object target) {
     42         return (T)net.sf.cglib.proxy.Enhancer.create(target.getClass(), new Callback(target));
     43     }
     44     
     45     public static <T> T enhance(Object target, Interceptor... injectInters) {
     46         return (T)net.sf.cglib.proxy.Enhancer.create(target.getClass(), new Callback(target, injectInters));
     47     }
     48     public static <T> T enhance(String singletonKey, Object target) {
     49         Object result = singleton.get(singletonKey);
     50         if (result == null) {
     51             result = enhance(target);
     52             singleton.put(singletonKey, result);
     53         }
     54         return (T)result;
     55     }
     56     
     57     public static <T> T enhance(String singletonKey, Object target, Interceptor... injectInters) {
     58         Object result = singleton.get(singletonKey);
     59         if (result == null) {
     60             result = enhance(target, injectInters);
     61             singleton.put(singletonKey, result);
     62         }
     63         return (T)result;
     64     }
     65     
     66 }
     67 
     68 
     69 import net.sf.cglib.proxy.MethodInterceptor;
     70 import net.sf.cglib.proxy.MethodProxy;
     71 
     72 import java.lang.reflect.Method;
     73 import java.util.HashSet;
     74 import java.util.Set;
     75 
     76 /**
     77  * Callback.
     78  */
     79 class Callback implements MethodInterceptor {
     80     
     81     private Object injectTarget = null;
     82     private final Interceptor[] injectInters;
     83     
     84     private static final Set<String> excludedMethodName = buildExcludedMethodName();
     85     private static final InterceptorManager interMan = InterceptorManager.me();
     86 
     87     public Callback() {
     88         this.injectInters = InterceptorManager.NULL_INTERS;
     89     }
     90     
     91     public Callback(Interceptor... injectInters) {
     92         checkInjectInterceptors(injectInters);
     93         this.injectInters = injectInters;
     94     }
     95     
     96     public Callback(Object injectTarget, Interceptor... injectInters) {
     97         if (injectTarget == null) {
     98             throw new IllegalArgumentException("injectTarget can not be null.");
     99         }
    100         checkInjectInterceptors(injectInters);
    101         this.injectTarget = injectTarget;
    102         this.injectInters = injectInters;
    103     }
    104     
    105     private void checkInjectInterceptors(Interceptor... injectInters) {
    106         if (injectInters == null) {
    107             throw new IllegalArgumentException("injectInters can not be null.");
    108         }
    109         for (Interceptor inter : injectInters) {
    110             if (inter == null) {
    111                 throw new IllegalArgumentException("interceptor in injectInters can not be null.");
    112             }
    113         }
    114     }
    115     
    116     public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    117         if (excludedMethodName.contains(method.getName())) {
    118             // if (method.getName().equals("finalize"))
    119             //     return methodProxy.invokeSuper(target, args);
    120             // return this.injectTarget != null ? methodProxy.invoke(this.injectTarget, args) : methodProxy.invokeSuper(target, args);
    121             
    122             // 保留上面注释部分,此处为优化
    123             if (this.injectTarget == null || method.getName().equals("finalize")) {
    124                 return methodProxy.invokeSuper(target, args);
    125             } else {
    126                 return methodProxy.invoke(this.injectTarget, args);
    127             }
    128         }
    129         
    130         if (this.injectTarget != null) {
    131             target = this.injectTarget;
    132             Interceptor[] finalInters = interMan.buildServiceMethodInterceptor(injectInters, target.getClass(), method);
    133             Invocation invocation = new Invocation(target, method, args, methodProxy, finalInters);
    134             invocation.useInjectTarget = true;
    135             invocation.invoke();
    136             return invocation.getReturnValue();
    137         }
    138         else {
    139             Class<?> targetClass = target.getClass();
    140             if (targetClass.getName().indexOf("$$EnhancerByCGLIB") != -1) {
    141                 targetClass = targetClass.getSuperclass();
    142             }
    143             Interceptor[] finalInters = interMan.buildServiceMethodInterceptor(injectInters, targetClass, method);
    144             Invocation invocation = new Invocation(target, method, args, methodProxy, finalInters);
    145             invocation.useInjectTarget = false;
    146             invocation.invoke();
    147             return invocation.getReturnValue();
    148         }
    149     }
    150 
    151     private static final Set<String> buildExcludedMethodName() {
    152         Set<String> excludedMethodName = new HashSet<String>();
    153         Method[] methods = Object.class.getDeclaredMethods();
    154         for (Method m : methods) {
    155             excludedMethodName.add(m.getName());
    156         }
    157         // getClass() registerNatives() can not be enhanced
    158         // excludedMethodName.remove("getClass");    
    159         // excludedMethodName.remove("registerNatives");
    160         return excludedMethodName;
    161     }
    162 }
    View Code

    封装后可以直接使用一句话, 还可用来增强已有对象

    1         AopDemo demo = Enhancer.enhance(AopDemo.class);

    示例

     1 @Before({PrivilegeInterceptor.class, LogInterceptor.class})
     2 public class AopDemo {
     3 
     4     public static void main(String[] args){
     5         AopDemo demo = Enhancer.enhance(AopDemo.class);
     6         demo.doSomething();
     7         demo.doOtherthing();
     8 
     9     }
    10 
    11     public void doOtherthing() {
    12         // 默认沿用Class的interceptor
    13         System.out.println("do 111111111111111");
    14     }
    15 
    16     @Clear(PrivilegeInterceptor.class)
    17     public void doSomething() {
    18         // 手动清除了权限Interceptor
    19         System.out.println("do 222222222222222");
    20     }
    21 }
     1 public class LogInterceptor implements Interceptor{
     2     @Override
     3     public void intercept(Invocation inv) {
     4         inv.invoke();
     5         System.out.println("Log记录入库");
     6     }
     7 }
     8 
     9 public class PrivilegeInterceptor implements Interceptor{
    10     @Override
    11     public void intercept(Invocation inv) {
    12         System.out.println("鉴权成功");
    13         inv.invoke();
    14     }
    15 }
    doOtherthing执行结果

    鉴权成功
    do 111111111111111
    Log记录入库

    doSomething执行结果

    do 222222222222222
    Log记录入库

    其他使用

    直接用来增强对象
    1         AopDemo demoSinle1 = Enhancer.enhance(AopDemo.getInstance());
    在enhance里new Interceptor
    1         AopDemo demo3 = Enhancer.enhance(AopDemo.class, new Interceptor() {
    2             @Override
    3             public void intercept(Invocation inv) {
    4                 System.out.println("new before");
    5                 inv.invoke();
    6                 System.out.println("new after");
    7             }
    8         });
    9         demo3.doSomething();
    在需要增强的方法上写@Before
    1     @Before(LogInterceptor.class)
    2     public void doOtherthing() {
    3     }
     
  • 相关阅读:
    在VS2005中 GridView导入Excel的两点小技巧
    ASP.NET页面事件:顺序与回传详解
    .NET泛型编程简介
    关于ASP.NET在IIS一些问题的经验总结
    ASP.NET生成静态页面实现方法
    ASP.NET 2.0防止同一用户同时登陆
    【经验总结】简陋无比的观察者模式实现
    javascript变量作用域一点总结
    javascript中"/"运算符常见错误
    【经验总结】构造函数的强制调用
  • 原文地址:https://www.cnblogs.com/xdecode/p/8076511.html
Copyright © 2011-2022 走看看