一、Cglib

CGLIB 呢, 相对于Java的代理来说, 更加灵活和富有弹性, 他的功能提供的更加的强大, 依靠callback实现的功能的增强.

通过这篇文章我相信你对于CGLIB的了解会提升一个档次的 . 本文开始从快速开始上手体验, 理解其核心模块,到源码分析其启动流程, 然后分析一些存在的问题.

官网地址: https://github.com/cglib/cglib

Demo

被增强的类

1
2
3
4
5
6
7
8
9
10
public class UserServiceImp {
public String getName(int id){
System.out.println("getName()"+id);
return "Tom";
}
public int getAge(int id){
System.out.println("getAge()"+id);
return 10;
}
}

增强

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class App {
public static void main(String[] args) {
// 设置字节码保存的地方.
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:/test");
//实例化Enhancer类生成器
Enhancer enhancer=new Enhancer();
//设置Enhancer要生成的目标类的父类
enhancer.setSuperclass(UserServiceImp.class);
//设置目标类执行方法的拦截器
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return "proxy" + proxy.invokeSuper(obj, args);
}
});
//利用enhancer生成目标类 UserServiceImp$$EnhancerByCGLIB$$b2b12b83@6df97b55
UserServiceImp userService1=(UserServiceImp) enhancer.create();
//生成的目标类调用方法,此时会被userServiceMethodInterceptor拦截,执行其中的intercept方法
userService1.getName(1);
//生成的目标类调用方法,此时会被userServiceMethodInterceptor拦截,执行其中的intercept方法
userService1.getAge(1);
}
}

二、Jdk动态代理

JDK动态代理基于拦截器和反射来实现。

JDK代理是不需要第三方库支持的,只需要JDK环境就可以进行代理,使用条件:

​ 1)必须实现InvocationHandler接口;

​ 2)使用Proxy.newProxyInstance产生代理对象;

​ 3)被代理的对象必须要实现接口;

Demo

1.接口

1
2
3
public interface IHello {
void sayHello();
}

2.实现类

1
2
3
4
5
6
public class HelloImpl implements IHello {
@Override
public void sayHello() {
System.out.println("Hello world!");
}
}

3. InvocationHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class JdkInvocationHandler implements InvocationHandler {
/** 目标对象 */
private Object target;
public JdkInvocationHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("------插入前置通知代码-------------");
Object rs = method.invoke(target,args); // 执行相应的目标方法
System.out.println("------插入后置处理代码-------------");
return rs;
}
}

4.Test

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
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;

/**
* 使用JDK动态代理的五大步骤:
* 1.通过实现InvocationHandler接口来自定义自己的InvocationHandler;
* 2.通过Proxy.getProxyClass获得动态代理类
* 3.通过反射机制获得代理类的构造方法,方法签名为getConstructor(InvocationHandler.class)
* 4.通过构造函数获得代理对象并将自定义的InvocationHandler实例对象传为参数传入
* 5.通过代理对象调用目标方法
*/
public class JdkProxyTest {
public static void main(String[] args)
throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
// =========================第一种==========================
// 1、生成$Proxy0的class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// 2、获取动态代理类
Class proxyClazz = Proxy.getProxyClass(IHello.class.getClassLoader(),IHello.class);
// 3、获得代理类的构造函数,并传入参数类型InvocationHandler.class
Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
// 4、通过构造函数来创建动态代理对象,将自定义的InvocationHandler实例传入
IHello iHello1 = (IHello) constructor.newInstance(new JdkInvocationHandler(new HelloImpl()));
// 5、通过代理对象调用目标方法
iHello1.sayHello();

// ==========================第二种=============================
/**
* Proxy类中还有个将2~4步骤封装好的简便方法来创建动态代理对象,
*其方法签名为:newProxyInstance(ClassLoader loader,Class<?>[] instance, InvocationHandler h)
*/
IHello iHello2 = (IHello) Proxy.newProxyInstance(IHello.class.getClassLoader(), // 加载接口的类加载器
new Class[]{IHello.class}, // 一组接口
new JdkInvocationHandler(new HelloImpl())); // 自定义的InvocationHandler
iHello2.sayHello();
}
}