JDK动态代理

本文最后更新于:2 个月前

在开始之前,先定义一个被代理接口IPerson和其实现类Person

1
2
3
4
5
package com.potato;

public interface IPerson {
void introduce();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.potato;

public class Person implements IPerson {
public String name;
public int age;

public Person(){}
public Person(String name,int age){
this.name = name;
this.age = age;
}

public void introduce(){
System.out.println(name+"今年"+ age +"岁了");
}

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

静态代理

直接贴代码了,缺点就是即使进行重复性的方法代理(如同样加入一个记录日志的功能),也需要在代理类中把方法一个一个都实现了,过于繁琐。思考一个解决方法,被代理对象能否直接知道外部的代理对象调用了什么方法呢,第一反应便是反射通过获取外部调用的方法名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.potato.Proxy;

import com.potato.Entity.IPerson;
import com.potato.Entity.Person;

public class StaticProxyTest {
public static void main(String[] args){
Proxy1 proxy1 = new Proxy1(new Person("potato",19));
proxy1.introduce();
}
public static class Proxy1 implements IPerson {
public IPerson proxy;
public Proxy1(){}
public Proxy1(IPerson proxy){
this.proxy = proxy;
}
public void introduce(){
this.proxy.introduce();
}
}
}

JDK底层为我们提供了一个解决方案,动态代理

动态代理

一个重要的方法,用于代理一个对象:

1
Proxy.newProxyInstance

跟进方法的定义去查看,需要一个类加载器对象,一个接口数组对象以及一个InvocationHandler对象

对于InvocationHandler对象,重写一下一个invoke方法,此处的invoke()方法就是在于解决静态代理中需要重复重写方法的缺陷,动态代理的好处就是能获取到外部调用的那个方法,然后通过反射来到内部来执行被代理对象的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public class PersonInvocationHandler implements InvocationHandler {
IPerson person;
public PersonInvocationHandler(){}
public PersonInvocationHandler(IPerson person){
this.person = person;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(person,args);
return null;
}
}

其中类加载对象和接口对象的获取还是比较定式的,如下传入参数并转型,即可创建一个代理对象personProxy,调用其introduce()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.potato;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class ProxyTest {
public static void main(String[] args){

IPerson person = new Person("potato",20);
InvocationHandler invocationHandler = new PersonInvocationHandler(person);
//要代理的接口
//需要一个类加载
//需要一个执行器handler
IPerson personProxy = (IPerson) Proxy.newProxyInstance(Person.class.getClassLoader(),Person.class.getInterfaces(),invocationHandler);
personProxy.introduce();
}
}

传参Class数组接口的参数位置也可以换为

1
2
3
IPerson personProxy = (IPerson) Proxy.newProxyInstance(Person.class.getClassLoader(),
new Class[]{IPerson.class},
invocationHandler);