jdk、cglib 动态代理案例

记录jdk、cglib学习案例

jdk动态代理案例

1、业务类
package com.saobai.designpatterns.proxy.business;

import com.saobai.User;

import java.util.*;

/**
 * @author saobai
 * @ClassName BusinessCrud.java
 * @Description  模拟crud
 * @createTime 2022-01-18 22:00:00
 */
public interface BusinessCrud {

    User query(String name);
    List<User> queryAll();
    void add(User user);
}

class BusinessCrudImpl implements BusinessCrud{

    final Map<String, User> map = new HashMap<>();
    {
        map.put("张三",User.builder().id(1).name("张三").sex(true).createTime(System.currentTimeMillis()).build());
        map.put("李四",User.builder().id(2).name("李四").sex(false).createTime(System.currentTimeMillis()).build());
        map.put("王五",User.builder().id(3).name("王五").sex(true).createTime(System.currentTimeMillis()).build());
        map.put("赵六",User.builder().id(4).name("赵六").sex(false).createTime(System.currentTimeMillis()).build());
    }

    @Override
    public User query(String name) {
        return map.get(name);
    }

    @Override
    public List<User> queryAll() {
        final Collection<User> values = map.values();
        final List<User> list = new ArrayList<>();
        for (int i = 0; i < values.size(); i++) {
            list.add((User) values.toArray()[i]);
        }
        return list;
    }

    @Override
    public void add(User user) {
        map.put(user.getName(),user);
    }
}
2、代理类
package com.saobai.designpatterns.proxy.business;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author gjq
 * @ClassName MySencedProxy.java
 * @Description 用jdk动态代理,给查询添加缓存操作
 * @createTime 2022-01-18 21:38:00
 */
 //代理类
public class MySecondProxy {
    public static Object getProxy(Object target, ConcurrentHashMap<String, Object> map) {
        //jdk动态代理
        /**newProxyInstance 方法参数介绍
         *  第一个参数  : 需要一个类加载器(当前类 MySecondProxy )
         *  第二个参数  : 需要加载的接口 对应的实现类
         *  第三个参数  : 调用处理器 ,用来获取代理对象中的方法和入参等(方法体的内容)
         */
        Object o = Proxy.newProxyInstance(MySecondProxy.class.getClassLoader(), target.getClass().getInterfaces(), new MySecondHandle(target, map));
        return o;
    }
}

//处理器 
@Slf4j
class MySecondHandle implements InvocationHandler {

    private Object obj;
    private ConcurrentHashMap<String, Object> map;

    public MySecondHandle(Object obj, ConcurrentHashMap<String, Object> map) {
        this.obj = obj;
        this.map = map;
    }

	//简单实现添加缓存的功能
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log.info("方法 {} 开始执行", method.getName());
        Object invoke = null;
        if ("queryAll".equals(method.getName())) {
            if (null == map.get("all")) {
            	
            	//利用反射机制,调用方法!!
	            //把 method 所代表的方法,当做是真实对象(obj)的方法调用,参数是args
                invoke = method.invoke(obj, args); 
                
                map.put("all", invoke);
            }else {
                invoke = map.get("all");
                log.info("执行查询缓存 {}",invoke);
            }
        } else {
            invoke = method.invoke(obj, args);
        }
        log.info("方法 {} 执行结果 {}", method.getName(), invoke);
        return invoke;
    }
}
3、测试jdk动态代理
package com.saobai.designpatterns.proxy.business;

import com.saobai.User;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author gjq
 * @ClassName TestCrud.java
 * @Description  给查询全部的方法 添加缓存【使用jdk动态代理】
 * @createTime 2022-01-18 22:23:00
 */
public class TestCrud {
private static final ConcurrentHashMap cache =  new ConcurrentHashMap<String, Object>();
    public static void main(String[] args) {

        BusinessCrud crud = new BusinessCrudImpl();
        //使用代理  【如果crud 参数写死,就是静态代理了】
        BusinessCrud proxy = (BusinessCrud) new MySecondProxy().getProxy(crud, cache);
        new Thread(()->{
            while (true){
                try {
                    Thread.sleep(20000); // 清空一次缓存
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                cache.clear();
            }
        }).start();

        new Thread(()->{
            while (true){
                proxy.queryAll();
                try {
                    Thread.sleep(5000); //执行一次查询
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

cglib动态代理案例

package com.samples.vehicles.web.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

//代理类
@Slf4j
public class CglibProxy{

    public Object getCglibProxy(Class<?> clazz){
        /**
         * Enhancer功能 与 jdk动态代理的 Proxy类似,它是一个字节码增强器,可以用来为无接口的类创建代理
         */
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(new MyInterceptor());
        return enhancer.create();
    }
}

class Test{
    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        Business proxy1 = (Business) proxy.getCglibProxy(Business.class);
        proxy1.add(1,2);
    }
}

//业务接口(测试案例)
class Business{
    public int add(int a,int b){
        return a+b;
    }
}

// cglib的拦截器,功能 类似于jdk动态代理的处理器(MySecondHandle)需要实现 InvocationHandler 的接口
@Slf4j
class MyInterceptor implements MethodInterceptor{

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //business 做业务增强 ....
        log.info("方法 {} 开始执行---",method.getName());
        //执行代理方法
        final Object obj = methodProxy.invokeSuper(o, objects);
        //执行结束后 逻辑...
        log.info("方法 {} 执行结果 {}",method.getName(),obj);
        return obj;
    }
}

总结

JDK动态代理是面向接口的代理模式;
CGLib动态代理是通过字节码底层继承要代理类来实现(如果被代理类被final关键字所修饰,则会创建代理失败)。
spring中默认采用jdk动态代理。

两者的区别与联系参考:
https://xuliugen.blog.csdn.net/article/details/82497594?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-1.queryctrv2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-1.queryctrv2&utm_relevant_index=2

猜你喜欢

转载自blog.csdn.net/qq_43473129/article/details/122574687