• 【动态代理】


    参考视频:
    AOP:https://www.bilibili.com/video/BV1Vf4y127N5?p=25
    cglib:https://www.bilibili.com/video/BV1G4411c7N4?p=94&vd_source=22e1d00fb0d54df3638f9bf26476387a

    什么是AOP?

    在这里插入图片描述


    动态代理两种实现方式:

    在这里插入图片描述

    在这里插入图片描述


    JDK动态代理案例:

    示例1:

    • 有一个用于登录的接口:Login
    • LoginImpl实现Login,实现了基本的登录login逻辑
    • 现在需要对login方法进行增强
    • 增强逻辑是,当方法是login的时候,对参数进行校验,如果校验通过再进行登录逻辑
    @Slf4j
    public class LoginJdkProxy {
        public static void main(String[] args) {
            Login loginProxy = (Login) Proxy.newProxyInstance(
                    LoginJdkProxy.class.getClassLoader(),
                    new Class[]{Login.class},
                    new InvocationHandler() {
    
                        Login login = new LoginImpl();
    
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            log.info("将要执行方法:{},参数:{}", method, Arrays.toString(args));
    
                            //如果是登录方法
                            if ("login".equals(method.getName())) {
                                if (StringUtils.isEmpty(args[0])) {
                                    return "用户名不能为空!";
                                }
    
                                Object invoke = method.invoke(login, args);
                                return invoke;
                            }
    
                            return method.invoke(login, args);
                        }
                    });
    
            System.out.println(loginProxy.login("admin", "123"));
            System.out.println(loginProxy.login("", "123"));
            System.out.println(loginProxy.toString());
        }
    }
    
    interface Login {
        String login(String username, String password);
    }
    
    class LoginImpl implements Login {
        @Override
        public String login(String username, String password) {
            if ("admin".equals(username)) {
                return "登录成功...";
            }
    
            return "登录失败...";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    在这里插入图片描述

    示例2:
    既然有接口就能代理,那HashMap应该是可以被代理的!因为有接口Map

    • 我想实现对map的get方法进行代理,如果取出的值中包含”死“,就替换成“**”
    public class HashMapJdkProxy {
        public static void main(String[] args) {
            Map<String, String> myHashMap = (Map<String, String>) Proxy.newProxyInstance(
                    HashMapJdkProxy.class.getClassLoader(),
                    new Class[]{Map.class},
                    new HashMapInvocationHandler(new HashMap<>()));
    
            myHashMap.put("aa", "死了");
            String aa = myHashMap.get("aa");
            
            System.out.println(aa);  // **了
        }
    }
    
    class HashMapInvocationHandler implements InvocationHandler {
        HashMap<String, String> hashMap;
    
        public HashMapInvocationHandler(HashMap<String, String> hashMap) {
            this.hashMap = hashMap;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //增强get方法
            if ("get".equals(method.getName())) {
                //如果获得的内容含有‘死’,则替换为‘**’
                String res = (String) method.invoke(hashMap, args);
    
                return res.replaceAll("死", "**");
            }
    
            return method.invoke(hashMap, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    Cglib代理

    介绍

    在这里插入图片描述

    例子

    例如:

    • 增强HashMap的get方法:使最终结果拼上“ 已被增强!”
    public class HashMapCglibProxy {
        public static void main(String[] args) {
        	//创建一个代理对象
        	// 1、工具类
            Enhancer enhancer = new Enhancer();
            // 2、设置父类
            enhancer.setSuperclass(HashMap.class);
            // 3、设置回调函数
            enhancer.setCallback(new MethodInterceptor() {
            
            	//定义一个成员变量,后面使用反射执行方法
                HashMap hashMap = new HashMap();
                
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    System.out.printf("调用的方法是%s, 参数有:%s\n",method.getName(), Arrays.toString(objects));
    
                    if ("get".equals(method.getName())){
                        String res = (String) method.invoke(hashMap, objects);
                        return res + " 已被增强!";
                    }
                    return method.invoke(hashMap,objects);
                }
            });
    		// 4、创建对象
            HashMap myHashMap = (HashMap) enhancer.create();
    
    		//调用代理对象的方法
            myHashMap.put("key","val");
            Object key = myHashMap.get("key");
            
            System.out.println(key);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在这里插入图片描述

    关于 Enhancer.setUseCache() 方法

    就是每次是否在方法区产生新的class,默认是true,在这种情况下,只要是代理同一个类型的对象,就不会产生新的class;而如果设为false,那么每次创建代理对象,他们的class都是不同的。如果设为false 可引发 OOM ,原因是Metaspace满了。

    例如:

    public class RegisterCglibProxy {
        public static void main(String[] args) {
            Enhancer enhancer1 = getEnhancer();
            Enhancer enhancer2 = getEnhancer();
    
            System.out.println("enhancer1.create().getClass()  --> " + enhancer1.create().getClass());
            System.out.println("enhancer2.create().getClass()  --> " + enhancer2.create().getClass());
    
            Register register1 = (Register) enhancer1.create();
            Register register2 = (Register) enhancer1.create();
            System.out.println("register1.getClass()  --> " + register1.getClass());
            System.out.println("register2.getClass()  --> " + register2.getClass());
    
            System.out.println(register1.register(""));
            System.out.println(register2.register("1232@qq.com"));
        }
    
        private static Enhancer getEnhancer() {
            Register register = new Register();
    
            Enhancer enhancer = new Enhancer();
    
            enhancer.setSuperclass(Register.class);
            enhancer.setUseCache(false);
            enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> method.invoke(register, objects));
            return enhancer;
        }
    }
    
    class Register {
        public boolean register(String qq) {
            return !StringUtils.isEmpty(qq);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    当enhancer.setUseCache(false)时:每创建一个对象,class都是不一样的。
    在这里插入图片描述

    当enhancer.setUseCache(true)或者不设置时:每创建一个对象,class都是一样的。
    在这里插入图片描述

  • 相关阅读:
    一个HTTPS转HTTP的Bug,他们忍了2年,原谅我无法接受,加班改了
    312.戳气球
    计算机网络产生的基础是什么
    写一个flutter程序2
    【目标检测】边界框回归与variances参数的作用
    学会编程, 而不是学会Java
    timezone 时区
    【java零基础入门到就业】第四天:Notepad++软件的下载和安装
    Stable Diffusion WebUI几种解决手崩溃的方法
    机器学习必修课 - 交叉验证 Cross-Validation
  • 原文地址:https://blog.csdn.net/m0_55155505/article/details/126373974