cglib代理常用接口和api

硅谷探秘者 ASM,java基础 509 0 0

  关于cglib代理的概念和原理,这里就不多说了,详细请参考以往的博客:

  本篇主要介绍cglib的主要(常用)的api。

一、MethodInterceptor

入门的helloword


import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;

class SampleClass{
    public void test(){
        System.out.println("test");
    }
    public void test2(){
        System.out.println("test2");
    }
}
public class test {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(SampleClass.class);
        enhancer.setCallback(new MethodInterceptor(){
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("before");
                Object res=methodProxy.invokeSuper(o, objects);
                System.out.println("after");
                return res;
            }
        });
        SampleClass proxy = (SampleClass) enhancer.create();
        proxy.test();
        proxy.test2();
    }
}

输出:

before
test
after
before
test2
after

  该种方法将代理SampleClass类的非final的所有成员方法。如果只想代理某个指定的方法,可以实现CallbackFilter接口,如下:

import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;

class SampleClass{
    public void test(){
        System.out.println("test");
    }
    public void test2(){
        System.out.println("test2");
    }
}
public class test {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(SampleClass.class);
        CallbackHelper callbackHelper = new CallbackHelper(SampleClass.class, new Class[0]) {
            @Override
            protected Object getCallback(Method method) {
                // 只代理方法名是test的方法
                if(method.getName().equals("test")){
                    return new MethodInterceptor(){
                        @Override
                        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                            System.out.print("代理---");
                            return methodProxy.invokeSuper(o, objects);
                        }
                    };
                }else{
                    return NoOp.INSTANCE;
                }
            }
        };
        enhancer.setCallbackFilter(callbackHelper);
        enhancer.setCallbacks(callbackHelper.getCallbacks());
        SampleClass proxy = (SampleClass) enhancer.create();
        proxy.test();
        proxy.test2();
    }
}

输出:

代理---test
test2

  这种方法可以指定具体代理某一个方法。

二、InvocationHandler

  InvocationHandler可以实现对接口的代理,类似与mybatis,代码中开发者只需要写一个接口和一个xml,mybatis会根据xml的描述信息,帮你生成对应的方法实现,参数的解析、sql的生成、发送、结果集的封装等都不用开发者去写。而其中的原理就是利用了代理模式。

  首先定义一个接口,这个接口里有各种返回值类型的方法。

import java.util.List;
public interface TestInterface {
    String testString(Integer id);
    int testInt(String value);
    List testList(Integer age,Integer g);
    SampleClass testSampleClass();
}

  用代理模式去实现这些方法。实现类交由cglib去动态创建。

import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class test2 {
    public static void main(String[] args)  {
        Class[] classes = {TestInterface.class};
        Enhancer enhancer = new Enhancer();
        enhancer.setInterfaces(classes);
        CallbackHelper callbackHelper = new CallbackHelper(Object.class, classes) {
            @Override
            protected Object getCallback(Method method) {
                // 只代理TestInterface中的方法
                if(method.getDeclaringClass() == TestInterface.class){
                    return new InvocationHandler() {
                        @Override
                        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                            System.out.print("参数:");
                            for (Object object : objects) {
                                System.out.print(object+"\t");
                            }
                            System.out.println();
                            Class<?> returnType = method.getReturnType();
                            if (returnType == int.class || returnType == Integer.class) {
                                // 返回值类型是整数类型
                                return 1;
                            }else if(returnType == String.class){
                                // 返回值类型是字符串
                                return "string";
                            }else if(returnType == List.class){
                                // 返回值类型是集合
                                ArrayList arrayList = new ArrayList();
                                arrayList.add("11");
                                return arrayList;
                            }
                            // ... 等等
                            else{
                                // 自定义类型
                                return returnType.newInstance();
                            }
                        }
                    };
                }else{
                    // 什么都不做
                    return NoOp.INSTANCE;
                }
            }
        };
        enhancer.setCallbackFilter(callbackHelper);
        enhancer.setCallbacks(callbackHelper.getCallbacks());
        TestInterface proxy = (TestInterface) enhancer.create();
        System.out.println("返回值:"+proxy.testInt("123"));;
        System.out.println("返回值:"+proxy.testList(1,1));;
        System.out.println("返回值:"+proxy.testString(1));;
        System.out.println("返回值:"+proxy.testSampleClass());;
    }
}

三、FixedValue

  该方法会对所有拦截的方法返回同样的值。

import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;

class SampleClass{
    public String test(){
        return "test";
    }
    public String test2(){
        return "test2";
    }
}
public class test {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(SampleClass.class);
        CallbackHelper callbackHelper = new CallbackHelper(SampleClass.class, new Class[0]) {
            @Override
            protected Object getCallback(Method method) {
                // 只代理返回值类型是String类型的方法,如果返回值类型不是String将会抛异常。
                if(method.getReturnType()==String.class){
                    return new FixedValue() {
                        @Override
                        public Object loadObject() throws Exception {
                            return "proxy ...";
                        }
                    };
                }else{
                    return NoOp.INSTANCE;
                }
            }
        };
        enhancer.setCallbackFilter(callbackHelper);
        enhancer.setCallbacks(callbackHelper.getCallbacks());
        SampleClass proxy = (SampleClass) enhancer.create();
        System.out.println(proxy.test());
        System.out.println(proxy.test2());
        System.out.println(proxy.toString());
        System.out.println(proxy.hashCode());
    }
}

输出:

proxy ...
proxy ...
proxy ...
1874154700

返回值是String类型的都返回同样的值。

四、ImmutableBean

  不可变的Bean。ImmutableBean允许创建一个原来对象的包装类,这个包装类是不可变的,任何改变底层对象的包装类操作都会抛出IllegalStateException。但是我们可以通过直接操作底层对象来改变包装类对象。

import net.sf.cglib.beans.ImmutableBean;

class SampleBean{
    SampleBean(){
    }
    SampleBean(int id){
        this.id = id;
    }
    private int id;
    public int getId(){
        return this.id;
    }
    public void setId(int id){
        this.id = id;
    }
}
public class test2 {
    public static void main(String[] args) {
        SampleBean bean = new SampleBean();
        bean.setId(1);
        SampleBean immutableBean = (SampleBean)ImmutableBean.create(bean);

        System.out.println(bean.getId());
        System.out.println(immutableBean.getId());
        bean.setId(2);
        System.out.println(bean.getId());
        System.out.println(immutableBean.getId());

        immutableBean.setId(3); // 包装类修改将会抛异常

        System.out.println(bean.getId());
        System.out.println(immutableBean.getId());
    }
}

输出:

1
1
2
2
Exception in thread "main" java.lang.IllegalStateException: Bean is immutable
    at com.example.SampleBean$$ImmutableBeanByCGLIB$$e23e512b.setId(<generated>)
    at com.example.test2.main(test2.java:31)

五、BeanGenerator

  cglib提供的一个操作bean的工具,使用它能够在运行时动态的创建一个bean。

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class test2 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        BeanGenerator beanGenerator = new BeanGenerator();
        beanGenerator.addProperty("id",int.class);
        Object myBean = beanGenerator.create();
        Method setter = myBean.getClass().getMethod("setId",int.class);
        setter.invoke(myBean,1);

        Method getter = myBean.getClass().getMethod("getId");
        System.out.println(getter.invoke(myBean));
    }
}

动态创建一个类,该类包含一个int类型的id属性,并包含get,set方法。

六、BeanMap

  BeanMap类实现了Java Map,将一个bean对象中的所有属性转换为一个String-to-Obejct的Java Map

import net.sf.cglib.beans.BeanMap;
import java.lang.reflect.InvocationTargetException;

class Bean{
    int id = 1;
    String name = "name";
    public int getId(){
        return this.id;
    }
    public String getName(){
        return this.name;
    }
}

public class test2 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Bean bean = new Bean();
        BeanMap beanMap = BeanMap.create(bean);
        Object id = beanMap.get("id");
        Object name = beanMap.get("name");
        System.out.println(id);
        System.out.println(name);
    }
}

输出:

1
name
猜你喜欢
ASM,java基础 573   关于cglib的概念以及api,请参考:初步探究cglib动态的原:http://www.jiajiajia.club/blog/artical/yjw520
算法基础 605 LocalDate1.获取当前时间LocalDatetoday=LocalDate.now();2.获取当前月份LocalDatetoday=LocalDate.now();intmonth=today.getMonthValue();3.获取当前日期LocalDatetoday=LocalDate.now();intday=today.getDayOfMonth();4.获取指定日期LocalD
java基础 2121 初步探究cglib动态的原之前我们说了一下jdk动态的原http://www.jiajiajia.club/weblog/blog/artical/60本章说一下cglib动态,做个
ASM,java基础 459 cglib指定只某个方法importnet.sf.cglib.proxy.*;importjava.lang.reflect.Method;classSampleClass
weblog 3033 前言 好久就开始关注cglib动态了,但是到今天才算是有点搞明白~cglib动态底层到了asm等字节码操作框架。不懂的可以先百度百度asm是干啥的,在这里也提供一些文章,但是可能比较深入
official 1058   BeanPostProcessor是SpringIOC容器给我们提供的一个扩展。,他的作主要是如果我们需要在Spring容器完成Bean的实例化、配置其他的初始化前后添加一些自己的逻辑处
工具 2202 /dependency2.java码调SoapClientclient=SoapClient.create("http://cwzf.zzcsjr.edu.cn/xysf/OrderView.asmx")//设
weblog 694 报错信息javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIXpathbuildingfailed:sun.security.provider.certpath.SunCertPathBuilderException:unabletofindvalidcertificationpathto
归档
2018年11月  12 2018年12月  33 2019年01月  28 2019年02月  28 2019年03月  32 2019年04月  27 2019年05月  33 2019年06月  6 2019年07月  12 2019年08月  12 2019年09月  21 2019年10月  8 2019年11月  15 2019年12月  25 2020年01月  9 2020年02月  5 2020年03月  16 2020年04月  4 2020年06月  1 2020年07月  7 2020年08月  13 2020年09月  9 2020年10月  5 2020年12月  3 2021年01月  1 2021年02月  5 2021年03月  7 2021年04月  4 2021年05月  4 2021年06月  1 2021年07月  7 2021年08月  2 2021年09月  8 2021年10月  9 2021年11月  16 2021年12月  14 2022年01月  7 2022年05月  1 2022年08月  3 2022年09月  2 2022年10月  2 2022年12月  5 2023年01月  3
标签
算法基础 linux 前端 c++ 数据结构 框架 数据库 计算机基础 储备知识 java基础 ASM 其他 深入理解java虚拟机 nginx git 消息中间件 搜索 maven redis docker dubbo vue 导入导出 软件使用 idea插件 协议 无聊的知识 jenkins springboot mqtt协议 keepalived minio mysql ensp 网络基础 xxl-job rabbitmq haproxy
目录
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。