简体   繁体   English

如何将 CGLib 代理转换为 Byte-Buddy

[英]How to convert CGLib proxy to Byte-Buddy

I'm struggling trying to convert the proxy I use with CGLib to BB.我正在努力尝试将我与 CGLib 一起使用的代理转换为 BB。 I have achieved easily the declared method interception but could not extend the objects as I need.我已经轻松实现了声明的方法拦截,但无法根据需要扩展对象。 In CGLib I use an interface and the interceptor.在 CGLib 中,我使用了一个接口和拦截器。 Here is my CGLib proxy code:这是我的 CGLib 代理代码:

public interface IObjectProxy {
    public OrientVertex ___getVertex();
    public String ___getRid();
    public void ___setVertex(OrientVertex v);

    public OrientVertex ___getEdge();
    public void ___setEdge(OrientEdge v);

    public Class<?> ___getBaseClass();
    public Object ___getProxiObject();
    public  boolean ___isDirty() ;
    public void ___removeDirtyMark();
    public void ___commit();
    public void ___rollback();
}

public class ObjectProxyFactory implements MethodInterceptor, IObjectProxy {

    private final static Logger LOGGER = Logger.getLogger(ObjectProxyFactory.class.getName());

    // the real object      
    private Object ___proxyObject;
    private Class<?> ___baseClass;
    // Vértice desde el que se obtiene el objeto.
//    private OrientVertex baseVertex;
    private OrientElement ___baseElement;
    private SessionManager ___sm;
    private boolean ___dirty = false;

    // constructor - the supplied parameter is an
    // object whose proxy we would like to create     
    private ObjectProxyFactory(Object obj, OrientElement e, SessionManager sm) {
        this.___baseClass = obj.getClass();
        this.___baseElement = e;
        this.___sm = sm;
    }

    // this method will be called each time      
    // when the object proxy calls any of its methods     
    @Override
    public Object intercept(Object o,
            Method method,
            Object[] args,
            MethodProxy methodProxy) throws Throwable {
        // response object
        Object res = null;

        // BEFORE
        // measure the current time         
//        long time1 = System.currentTimeMillis();
//        System.out.println("intercepted: " + method.getName());
        // modificar el llamado
        switch (method.getName()) {
            case "___getVertex":
                res = this.___getVertex();
                break;
            case "___getRid":
                res = this.___getRid();
                break;
            case "___getProxiObject":
                res = this.___getProxiObject();
                break;
            case "___getBaseClass":
                res = this.___getBaseClass();
                break;
            case "___isDirty":
                res = this.___isDirty();
                break;
            case "___removeDirtyMark":
                this.___removeDirtyMark();
                break;
            case "___commit":
                this.___commit();
                break;
            default:
                // invoke the method on the real object with the given params
//                res = methodProxy.invoke(realObj, args);
                res = methodProxy.invokeSuper(o, args);

                // verificar si hay diferencias entre los objetos.
                this.commitObjectChange();

                break;
        }

        // AFTER
        // print how long it took to execute the method on the proxified object
//        System.out.println("Took: " + (System.currentTimeMillis() - time1) + " ms");
        // return the result         
        return res;
    }

    private void setProxyObject(Object po) {
        this.___proxyObject = po;
    }

    public static <T> T createProxy(T obj, OrientElement ov, SessionManager sm) {
        // this is the main cglib api entry-point
        // this object will 'enhance' (in terms of CGLIB) with new capabilities
        // one can treat this class as a 'Builder' for the dynamic proxy
        Enhancer e = new Enhancer();

        // the class will extend from the real class
        e.setSuperclass(obj.getClass());
        // we have to declare the interceptor  - the class whose 'intercept'
        // will be called when any method of the proxified object is called.
        ObjectProxyFactory opf = new ObjectProxyFactory(obj,ov, sm);
        e.setCallback(opf);
        e.setInterfaces(new Class[]{IObjectProxy.class});

        // now the enhancer is configured and we'll create the proxified object
        T proxifiedObj = (T) e.create();

        opf.setProxyObject(proxifiedObj);

        // the object is ready to be used - return it
        return proxifiedObj;
    }

    /**
     * retorna el vértice asociado a este proxi o null en caso que no exista uno.
     *
     * @return
     */
    @Override
    public OrientVertex ___getVertex() {
        if (this.___baseElement.getElementType().equals("Vertex")) {
            return (OrientVertex) this.___baseElement;
        } else {
            return null;
        }
    }

    /**
     * retorna el vértice asociado a este proxi o null en caso que no exista uno.
     *
     * @return
     */
    @Override
    public String ___getRid() {
        if (this.___baseElement != null) {
            return this.___baseElement.getId().toString();
        } else {
            return null;
        }
    }

    /**
     *
     * establece el elemento base como un vértice.
     *
     * @param v
     */
    @Override
    public void ___setVertex(OrientVertex v) {
        this.___baseElement = v;
    }

    /**
     * retorna el vértice asociado a este proxi o null en caso que no exista uno.
     *
     * @return
     */
    @Override
    public OrientVertex ___getEdge() {
        if (this.___baseElement.getElementType().equals("Edge")) {
            return (OrientVertex) this.___baseElement;
        } else {
            return null;
        }
    }

    /**
     *
     * establece el elemento base como un vértice.
     *
     * @param v
     */
    @Override
    public void ___setEdge(OrientEdge e) {
        this.___baseElement = e;
    }

    @Override
    public Object ___getProxiObject() {
        return this.___proxyObject;
    }

    @Override
    public Class<?> ___getBaseClass() {
        return this.___baseClass;
    }

    private void commitObjectChange() {
        LOGGER.log(Level.INFO, "iniciando commit interno....");
        // si ya estaba marcado como dirty no volver a procesarlo.
        if (!___dirty) {

            ....
            ....
            lot's of code here
            ...
            ...

            if (this.___dirty) {
                // agregarlo a la lista de dirty para procesarlo luego
                this.___sm.setAsDirty(this);
                System.out.println("Objeto marcado como dirty! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
            }
        }
    }

    @Override
    public boolean ___isDirty() {
        return ___dirty;
    }

    @Override
    public void ___removeDirtyMark() {
        this.___dirty = false;
    }

    @Override
    public void ___commit() {
        if (this.___dirty) {
            ....
            ....
            lot's of code here
            ...
            ...
            // quitar la marca de dirty
            this.___dirty = false;
        }
    }

    @Override
    public void ___rollback() {

    }

}

This work fine.这工作很好。 Every call to the subclassed object with the interface method are delegated to the proxy class that extend the object.使用接口方法对子类对象的每次调用都委托给扩展该对象的代理类。 In that object I store reference other objects relative to the entity, the vertex in the graph database and the state.在该对象中,我存储了与实体、图形数据库中的顶点和状态相关的其他对象的引用。 What I must do to implement this in BB?我必须做什么才能在 BB 中实现这一点?

================================== ==================================

Well, today I have this that sould work, but not.好吧,今天我有这个可行的方法,但不是。 The ObjectProxyFactory was divided in two class: ObjectProxyFactory 分为两类:

public class ObjectProxy implements IObjectProxy {

   private final static Logger LOGGER = Logger.getLogger(ObjectProxy.class.getName());

   // the real object      
   private Object ___proxyObject;
   private Class<?> ___baseClass;
   // Vértice desde el que se obtiene el objeto.
   //    private OrientVertex baseVertex;
   private OrientElement ___baseElement;
   private SessionManager ___sm;
   private boolean ___dirty = false;

   // constructor - the supplied parameter is an
   // object whose proxy we would like to create     
   public ObjectProxy(Object obj, OrientElement e, SessionManager sm) {
       this.___baseClass = obj.getClass();
       this.___baseElement = e;
       this.___sm = sm;
   }

   public ObjectProxy(Class c, OrientElement e, SessionManager sm) {
       this.___baseClass = c;
       this.___baseElement = e;
       this.___sm = sm;
   }

   // this method will be called each time      
   // when the object proxy calls any of its methods
   @RuntimeType
   public Object intercept(@SuperCall Callable<?> zuper, @This Object thiz, @Origin Method method) throws Exception {

       // response object
       Object res = null;

       // BEFORE
       // measure the current time         
       // long time1 = System.currentTimeMillis();
       // System.out.println("intercepted: " + method.getName());
       // modificar el llamado
       switch (method.getName()) {
           case "___getVertex":
              res = this.___getVertex();
              break;
           case "___getRid":
              res = this.___getRid();
              break;
           case "___getProxiObject":
              res = this.___getProxiObject();
              break;
          case "___getBaseClass":
              res = this.___getBaseClass();
              break;
          case "___isDirty":
              res = this.___isDirty();
              break;
          case "___removeDirtyMark":
              this.___removeDirtyMark();
              break;
          case "___commit":
              this.___commit();
              break;
          default:
              // invoke the method on the real object with the given params

              res = zuper.call();

              // verificar si hay diferencias entre los objetos.
              this.commitObjectChange();

              break;
       }

      // AFTER
      // print how long it took to execute the method on the proxified object
      // System.out.println("Took: " + (System.currentTimeMillis() - time1) + " ms");
      // return the result         
      return res;
   }
...
// the same as above 
...
}

Now I have the ObjectProxyFactory that make glue:现在我有了制作胶水的 ObjectProxyFactory:

public class ObjectProxyFactory {
    private final static Logger LOGGER = Logger.getLogger(ObjectProxyFactory.class .getName());

    /**
     * Devuelve un proxy a partir de un objeto existente y copia todos los valores del objeto original al 
     * nuevo objecto provisto por el proxy
     * @param <T>
     * @param o
     * @param oe
     * @param sm
     * @return 
     */
    public static <T> T create(T o, OrientElement oe, SessionManager sm ) {
        T po = null;
        try {
            ObjectProxy bbi = new ObjectProxy(o,oe,sm);
            po = (T) new ByteBuddy()
                    .subclass(o.getClass())
                    .implement(IObjectProxy.class)
                    .method(isDeclaredBy(IObjectProxy.class))
                    .intercept(MethodDelegation.to(bbi))
                    .make()
                    .load(o.getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
                .getLoaded().newInstance();

    } catch (InstantiationException ex) {
          Logger.getLogger(ObjectProxyFactory.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        Logger.getLogger(ObjectProxyFactory.class.getName()).log(Level.SEVERE, null, ex);
    }
    return po;
}

/**
 * Devuelve un proxy a partir de una definición de clase.
 * @param <T>
 * @param c
 * @param ov
 * @param sm
 * @return 
 */
public static <T> T create(Class<T> c, OrientElement ov, SessionManager sm ) {
    T po = null;
    try {
        ObjectProxy bbi = new ObjectProxy(c,ov,sm);
        po = (T) new ByteBuddy()
                .subclass(c)
                .implement(IObjectProxy.class)
                .method(isDeclaredBy(IObjectProxy.class))
                .intercept(MethodDelegation.to(bbi))
                .make()
                .load(c.getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
                .getLoaded().newInstance();

    } catch (InstantiationException ex) {
        Logger.getLogger(ObjectProxyFactory.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        Logger.getLogger(ObjectProxyFactory.class.getName()).log(Level.SEVERE, null, ex);
    }
     return po;
   }
}

With this code, it is throwing this exception:使用此代码,它抛出此异常:

java.lang.IllegalArgumentException: Cannot inject classes into the bootstrap class loader at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection.(ClassInjector.java:161) ... java.lang.IllegalArgumentException: 无法在 net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection.(ClassInjector.java:161) 处将类注入引导类加载器...

Well.好。 Finally to solve the second part of the previous post I use:最后解决我使用的上一篇文章的第二部分:

.load(getSystemClassLoader(), ClassLoadingStrategy.Default.INJECTION)

and it work!它起作用了!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM