【动态代理】

参考视频:
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 "登录失败...";
    }
}

在这里插入图片描述

示例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);
    }
}

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);
    }
}

在这里插入图片描述

关于 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);
    }
}

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值