jdk动态代理,cglib

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的法的功能称为java语言的反射机制。

反射机制:具有操作字节码文件的能力

  1. java.lang.Class :保留一个类的全部信息
  2. java.util.reflect.Constructor:保存了一个类当中的构造方法的所有信息
  3. java.util.reflect.Method:保存了一个类当中的方法的所有信息
  4. java.util.reflect.Field:保存了一个类当中的成员属性的所有信息

动态代理

动态代理简单来说就是在程序执行过程中,创建代理对象,通过代理对象执行方法,给目标类的方法增加额外的功能,也叫做功能增强。

JDK动态代理的实现步骤

  1. 首先我们需要有一个目标类,在目标类的基础上通过动态代理实现功能增强
  2. 创建InvocationHandler接口的实现类,在这个类中实现invoke方法,在invoke方法中实现给目标类的方法增强功能
  3. 通过JDK中的Proxy创建代理,通过代理调用目标类中的方法,实现功能增强

JDK动态代理的代码实现

  1. 创建一个接口
    1
    2
    3
    4
    public interface SomeService {
    void doSome();
    void doOther();
    }
  2. 目标类实现这个接口:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class SomeServiceImpl implements SomeService {

    @Override
    public void doSome() {
    System.out.println("执行doSome");
    }

    @Override
    public void doOther() {
    System.out.println("执行doOther");
    }
    }
  3. 创建一个工具类,里面是增强的功能:
1
2
3
4
5
6
7
8
9
10
11
public class ServiceTools {

public static void doLog(){
System.out.println("方法的执行时间:" + new Date());
}

public static void doTrans(){
System.out.println("方法执行完毕,提交事务");
}

}
  1. 创建InvocationHandler接口的实现类
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
public class MyInvocationHandler implements InvocationHandler {
//目标对象
private Object target;

public MyInvocationHandler(Object target) {
this.target = target;
}

//通过代理对象执行方法时,会调用执行这个invoke()方法

/**
*
* @param proxy 代理类实例
* @param method 被代理的方法
* @param args 方法的参数数组
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

System.out.println("执行MyInvocationHandler中的invoke方法");

//打印被调用的目标类中的方法名
System.out.println(method.getName());

Object res = null;

//实现的增强的功能
ServiceTools.doLog();

//执行目标类方法,通过Method实现
res = method.invoke(target, args);

//增强的功能
ServiceTools.doTrans();

//返回目标方法的执行结果
return res;
}
}
  1. 通过Proxy创建代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) {
//创建目标对象
SomeService target = new SomeServiceImpl();

//创建InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(target);

//使用Proxy创建代理
SomeService proxy = (SomeService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);

//通过代理执行方法,会调用handle中的invoke()方法
proxy.doSome();
}

通用类:

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
public class JdkProxy implements InvocationHandler {

private Object target;

public JdkProxy(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long starTime = System.nanoTime();
Object result = method.invoke(this.target, args);
long endTime = System.nanoTime();
System.out.println(this.target.getClass() + ".m1()方法耗时(纳秒):" + (endTime - starTime));
return result;
}

/**
* 用来创建targetInterface接口的代理对象
*
* @param target 需要被代理的对象
* @param targetInterface 被代理的接口
* @param <T>
* @return
*/
public static <T> T createProxy(Object target, Class<T> targetInterface) {
if (!targetInterface.isInterface()) {
throw new IllegalStateException("targetInterface必须是接口类型!");
} else if (!targetInterface.isAssignableFrom(target.getClass())) {
throw new IllegalStateException("target必须是targetInterface接口的实现类!");
}
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new JdkProxy(target));
}

public static <T> T createProxy(Object target) {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new JdkProxy(target));
}
}

使用:
IService proxy = JdkProxy.createProxy(new SomeServiceImpl(), SomeService.class);

IService proxy1 = JdkProxy.createProxy(new SomeServiceImpl());

总结一下动态代理实现过程:

  1. 通过getProxyClass0()生成代理类。
  2. 通过Proxy.newProxyInstance()生成代理类的实例对象,创建对象时传入InvocationHandler类型的实例。
  3. 调用新实例的方法,即此例中的m1(),m2(),即原InvocationHandler类中的invoke()方法。

动态代理的作用:

  1. 在目标类源代码不改变的情况下,增加目标类的功能
  2. 当涉及到多个方法都需要增加某些同样的功能时,使用动态代理可以减少代码的重复
  3. 可以使目标类专注于业务逻辑代码
  4. 实现解耦合,让业务功能和日志、事务和非事务功能分离

为什么jdk动态代理必须实现接口:

1
2
3
4
5
6
7
8
9
 //反编译出来看,继承了Proxy类,所以没法再继承了,java是单继承
String path = "logs/$Proxy0.class";
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0",
IServiceImpl.class.getInterfaces());

FileOutputStream out = new FileOutputStream(path);
out.write(classFile);
out.flush();
out.close();

cglib

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
public static void main(String[] args) {
//使用Enhancer来给某个类创建代理类,步骤

//1.创建Enhancer对象
Enhancer enhancer = new Enhancer();
//2.通过setSuperclass来设置父类型,即需要给哪个类创建代理类
enhancer.setSuperclass(Service1.class);
/*
3.设置回调,需实现org.springframework.cglib.proxy.Callback接口,
此处我们使用的是org.springframework.cglib.proxy.MethodInterceptor,
也是一个接口,实现了Callback接口,
当调用代理对象的任何方法的时候,都会被MethodInterceptor接口的invoke方法处理
*/
/**
* 此处
* 1. MethodInterceptor 拦截所有方法
* 2. 拦截所有方法并返回自定义的值(FixedValue)
* 3. 直接放行,不做任何操作(NoOp.INSTANCE)
* 4. 不同的方法使用不同的拦截器(CallbackFilter)
* */
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
/**
* 代理对象方法拦截器
* @param o 代理对象
* @param method 被代理的类的方法,即Service1中的方法
* @param objects 调用方法传递的参数
* @param methodProxy 方法代理对象
* @return
* @throws Throwable
*/
System.out.println("调用方法:" + method);
//可以调用MethodProxy的invokeSuper调用被代理类的方法
Object result = methodProxy.invokeSuper(o, objects);
return result;
}
});
//4.获取代理对象,调用enhancer.create方法获取代理对象,这个方法返回的是Object类型的,所以需要强转一下
Service1 proxy = (Service1) enhancer.create();
//5.调用代理对象的方法
proxy.m1();
proxy.m2();

Service1 proxy1 = CglibProxy.createProxy(new Service1());
proxy1.m2();
proxy1.m1();
}

通用方法

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
public class CglibProxy implements MethodInterceptor {

//目标对象
private Object target;

public CglibProxy(Object target) {
this.target = target;
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
long starTime = System.nanoTime();
//调用被代理对象(即target)的方法,获取结果
Object result = method.invoke(target, objects); //@1
long endTime = System.nanoTime();
System.out.println(method + ",耗时(纳秒):" + (endTime - starTime));
return result;
}

/**
* 创建任意类的代理对象
*
* @param target
* @param <T>
* @return
*/
public static <T> T createProxy(T target) {
CglibProxy cglibProxy = new CglibProxy(target);
Enhancer enhancer = new Enhancer();
enhancer.setCallback(cglibProxy);
enhancer.setSuperclass(target.getClass());
return (T) enhancer.create();
}
}

Service1

1
2
3
4
5
6
7
8
9
10
11

public class Service1 {

public void m1() {
System.out.println("m1");
}

public void m2() {
System.out.println("m2");
}
}

jdk动态代理,cglib
https://vaughnn.github.io/posts/6bee818d/
作者
vaughnn
发布于
2022年6月12日
更新于
2024年2月12日