记录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动态代理。