• CGLIB(code Generation Library),Code生成类库
    • CGLIB 动态代理不限定是否具有接口,可以对任意操作进行增强
    • CGLIB 动态代理不需要原始被代理对象,动态创建出新的代理对象

    代理方法:

    1. public class UserServiceCglibProxy {
    2. public static UserService createUserServiceCglibProxy(Class clazz) {
    3. // 在内存中创建字节码
    4. Enhancer enhancer = new Enhancer();
    5. // 创建对象 最后需要强转成UserService对象,只有父子类可以转,当前UserService是一个接口,只有设置字节码对象父类为UserServiceImpl实现类
    6. enhancer.setSuperclass(clazz);
    7. // 需要调用原始方法
    8. enhancer.setCallback(new MethodInterceptor() {
    9. @Override
    10. //代理出来类的对象 //原始调用方法 //args // 代理方法,造出字节码中的方法
    11. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    12. Object ret = methodProxy.invokeSuper(o, objects);
    13. if(method.getName().equals("save")){
    14. System.out.println("刮大白");
    15. System.out.println("贴墙纸");
    16. }
    17. return ret;
    18. }
    19. });
    20. return (UserService)enhancer.create();
    21. }
    22. }
    23. 启动方法
    24. public class App {
    25. public static void main(String[] args) {
    26. UserService userService = UserServiceCglibProxy.createUserServiceCglibProxy(UserServiceImpl.class);
    27. userService.save();
    28. }
    29. }

    1、创建字节码对象Enhancer enhancer = new Enhancer();
    2、应为最后需要返回类型为UserService对象,所以需要强转类型,强转类型必须是父子类,但是当前类(UserService是一个接口,无法转换),那么我们必须手动设置字节码的父类:enhancer.setSuperclass(clazz);需要传入父类字节码对象
    3、增强方法必须得调用原始方法,在原始方法操作上调用方法。调用原始方法:enhancer.setCallback(需要参数new MethodInterceptor)
    MethodInterceptor需要参数,使用匿名内部类,和JDK Proxy相似,规则:
    intercept方法(Object o, Method method, Object[] objects, MethodProxy methodProxy):
    参数1:代理出来类的对象
    参数2:原始调用方法
    参数3:args参数
    参数4:代理方法,造出字节码中的方法

    因为需要调用父类方法,而当前参数1是代理出来的对象,所以我们必须使用methodProxy.invokeSuper(o, objects); 代理出来的方法.invokerSuper调用父类的方法(就是原始方法)
    ps:当前增强是对父类所有方法进行了增强,而我们执行时代理对象有两个操作:toString,hashCode,作用是为代理对象生成地址值,所以如果我们直接对增强方法,每次也会对这两个方法进行增强,导致多次运行增强方法。所以我们进行判断,对需要的方法进行增强

    图片.png