java代理的深入浅出(二)-CGLIB

java代理的深入浅出(二)-CGLIB

1.基本原理

CGLIB的原理就是生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中拦截所有父类方法的调用,拦截下来交给设置的MethodInterceptor去执行。 由于是采用继承来实现的代理,所以不能对final修饰的类进行代理,其它都可以代理。

子类的生成它采用了非常底层的字节码技术(ASM节码处理框架),转换字节码来完成。它要求必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

代理一个类一般会动态生成三个类

第一个是生成的新子类,对原始类里每一个方法都会在动态的子类里生成一个对应的MethodProxy。

另外两个动态生成的FastClass类,一个是针对应原始类的方法生成方法索引表,一个针对应新生成子类的方法生成方法索引表。这2个额外生成的类主要作用在于当我们调用一个方法时,不通过反射来调用,而是通过类似于数组下标的方式来定位方法,直接进行类方法的执行。因此CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。

2.核心类

cglib主要包含4个概念,BeanGenerator、Enhancer、MethodInterceptor、LazyLoader、Dispatcher。
beangenerator主要用于动态生成一个类的子类,可以给子类动态添加一些成员变量,自动生成Getter、Setter方法。缺点是它只能生成含默认构造函数的子类。

BeanGenerator gen = BeanGenerator();
gen.setSuperclass(SuperClass.class);
gen.addProperty("name", String.class);
Class subClazz = (Class)gen.createClass();
SuperClass obj = (SuperClass)gen.create();

enhancer用于实现某个方法调用的aop功能。enhancer生成对象会包含很多cglib自动添加进去的属性,所以最后生成的对象会比较大。

MethodInterceptor

public class MethodInterceptorImpl implements MethodInterceptor{
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(obj, args);
}
}

//代理invoke方法
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallbacks(new Callback[]{NoOp.INSTANCE, new MethodInterceptorImpl()});
enhancer.setCallbackFilter(new CallbackFilter() {
@Override
public int accept(Method method) {
//只拦截Algorithm接口定义的invoke方法
if(method.getName().equals("invoke"))
return 1;
return 0;
}
});
enhancer.setUseFactory(false);
//new 出对象
Object proxy = enhancer.create();

lazyLoader是cglib的代理延迟初始化接口。当接口方法被第一次调用时,才确定实际要访问的对象。

public class ConcreteClassLazyLoader implements LazyLoader{

    public class PropertyBean {
        private String propertyName;  
        public String getPropertyName() {
            return propertyName;
        }
        public void setPropertyName(String propertyName) {
            this.propertyName = propertyName;
        }
    }

    @Override
    public Object loadObject() throws Exception {  
        System.out.println("LazyLoader loadObject() ...");  
        PropertyBean bean=new PropertyBean();  
        bean.setPropertyName("lazy-load object propertyName!");  
        return bean;  
    }

    public static void main(String[] args){
        Enhancer enhancer=new Enhancer();  
        enhancer.setSuperclass(PropertyBean.class);  
        PropertyBean propertyBean = (PropertyBean)enhancer.create(PropertyBean.class,new ConcreteClassLazyLoader());  

        //此处会回调loadObject
        System.out.println(propertyBean.getPropertyName());

        System.out.println("after...");  
        //之后不再回调loadObejct,直接访问第一次返回的对象 
        System.out.println(propertyBean.getPropertyName());  
    }
}

Dispatcher功能与LazyLoader相同,只是dispatcher每次都会被回调。

public class ConcreteDispatcher implements Dispatcher{

    public class PropertyBean {
        private String propertyName;  
        public String getPropertyName() {
            return propertyName;
        }
        public void setPropertyName(String propertyName) {
            this.propertyName = propertyName;
        }
    }

    @Override
    public Object loadObject() throws Exception {  
        System.out.println("Dispatcher loadObject() ...");  
        PropertyBean bean=new PropertyBean();  
        bean.setPropertyName("Dispatcher object propertyName!");  
        return bean;  
    }

    public static void main(String[] args){
        Enhancer enhancer=new Enhancer();  
        enhancer.setSuperclass(PropertyBean.class);  
        PropertyBean propertyBean = (PropertyBean)enhancer.create(PropertyBean.class,new ConcreteDispatcher());  

        //此处会回调loadObject
        System.out.println(propertyBean.getPropertyName());

        System.out.println("after...");  
        //每次都回调loadObejct
        System.out.println(propertyBean.getPropertyName());  
    }
}

3.示例

目标类 CrudServiceImpl

public class CrudServiceImpl implements CrudService {
    @Override
    public Long create(String content) {
        System.out.println("create......");
        return 1L;
    }

    @Override
    public List<String> retrieve(String condition) {
        System.out.println("retrieve......");
        return null;
    }

    @Override
    public boolean update(Long id, String content) {
        System.out.println("update......");
        return true;
    }

    @Override
    public boolean delete(Long id) {
        System.out.println("delete......");
        return false;
    }
}

拦截处理类

public class MyMethodIntercepter implements MethodInterceptor{

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("brfore1 cglib invoke");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("after2 cglib invoke");
        return result;
    }
}

回调过滤类

public class ConcreteClassCallbackFilter implements CallbackFilter {
    @Override
    public int accept(Method method) {
        if(method.getName().equals("create")){
            return 1;
        }
        return 0;
    }
}

生成动态代理类

public class TestCglib {
    public static void main(String[] args){
        Enhancer enhancer = new Enhancer(); 
        enhancer.setSuperclass(CrudServiceImpl.class); 
        enhancer.setCallbacks(new Callback[]{NoOp.INSTANCE,new MyMethodIntercepter()});
        enhancer.setCallbackFilter(new ConcreteClassCallbackFilter()); 
        CrudService proxy = (CrudService)enhancer.create();
        System.out.println("proxy class name>>>>>"+proxy.getClass().getName());
        System.out.println(proxy.create("ddd"));
        System.out.println("==============================");
        System.out.println(proxy.delete(1L));
    }
}

反编译动态代理类

用agent(premain)将加载类导出到指定目录下,加下面的代码打包到jar里,增加MANIFEST.INF描述内容

Can-Redefine-Classes: true
Premain-Class: com.longchao.agent.CustomAgent

在程序启动的vm参数里加agent参数,-javaagent:D:/work/code/middleware/study/agent.jar

public class CustomAgent implements ClassFileTransformer {

    public static void premain(String agentArgs, Instrumentation inst) {
        inst.addTransformer(new CustomAgent());
    }

    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        if (!className.startsWith("java") && !className.startsWith("sun")) {
            // 既不是java也不是sun开头的
            // 导出代码
            int lastIndexOf = className.lastIndexOf("/") + 1;
            String fileName = className.substring(lastIndexOf) + ".class";
            exportClazzToFile("d:/aop/", fileName, classfileBuffer);
            System.out.println(className + " --> EXPORTED Succeess!");
        }
        return classfileBuffer;
    }

    /**
     * @param dirPath  目录以/结尾,且必须存在
     * @param fileName
     * @param data
     */
    private void exportClazzToFile(String dirPath, String fileName, byte[] data) {
        try {
            File file = new File(dirPath + fileName);
            if (!file.exists()) {
                file.createNewFile();
            }
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(data);
            fos.close();
        } catch (Exception e) {
            System.out.println("exception occured while doing some file operation");
            e.printStackTrace();
        }
    }
}

4.总结

BeanGenerator适合给子类加成员变量
MethodInterceptor 适合做方法拦截
LazyLoader、Dispatcher适合做对象路由

ps:代码的地址:https://github.com/zhulongchao/proxy.git

原文地址:https://www.cnblogs.com/zhulongchao/p/5516258.html