java动态代理

java代理机制

作用:

  • 对于不能或不想直接引用的对象,通过代理访问
  • 通过代理去掉不能看到的内容
  • 通过代理提供额外服务

Subject: 公共对外方法,表现为一个接口
RealSubject: 真正的方法实现
Proxy: 用来代理和封装RealSubject

静态代理

sqlInterface.java

1
2
3
4
5
6
package ProxyTest;

public interface sqlInterface {
public sqlInterface select();
public sqlInterface update();
}

sql1.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package ProxyTest;

public class sql1 implements sqlInterface {

@Override
public sqlInterface select() {
System.out.println("selected");
return this;
}

@Override
public sqlInterface update() {
System.out.println("updated");
return this;
}
}

sqlProxy.java

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
package ProxyTest;

import java.util.Date;

public class sqlProxy implements sqlInterface{

private sqlInterface sql = null;

public sqlProxy(sqlInterface sql) {
this.sql = sql;
}

@Override
public sqlInterface select() {
before();
sql.select();
after();
return null;
}

@Override
public sqlInterface update() {
before();
sql.update();
after();
return null;
}

private void before() {
System.out.println("数据库已连接");
String start = String.format("log start time [%s] ", new Date());
System.out.println(start);
}

private void after() {
String end = String.format("log end time [%s] ", new Date());
System.out.println(end);
System.out.println("数据库已断开");
}
}

ProxyTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package ProxyTest;

public class ProxyTest {
public static void main(String[] args) {
sql1 sql = new sql1();
sqlProxy sqlProxy = new sqlProxy(sql);
sqlProxy.select();
}
}

/*
output
数据库已连接
log start time [Wed Nov 18 20:53:43 CST 2020]
selected
log end time [Wed Nov 18 20:53:43 CST 2020]
数据库已断开
*/

从上的代码来看,这里使用了代理模式来实现了一个log功能。
静态代理虽然简单,但可以看到,因为接口是被限定死的,如果未来更改接口,其维护量可想而知…

动态代理

静态代理是写死的,那么动态代理顾名思义,其是动态生成的。

jdk原生动态代理

下面是上面的静态代理代码修改为动态代理后

sqlLogHandler.java

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
package ProxyTest;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;

public class sqlLogHandler implements InvocationHandler {

private sqlInterface sql = null;

public sqlLogHandler(sqlInterface sql) {
this.sql = sql;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object obj = method.invoke(sql, args);
after();
return obj;
}

private void before() {
System.out.println("数据库已连接");
String start = String.format("log start time [%s] ", new Date());
System.out.println(start);
}

private void after() {
String end = String.format("log end time [%s] ", new Date());
System.out.println(end);
System.out.println("数据库已断开");
}
}

sqlProxyGetter.java

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

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

public class sqlProxyGetter {

public static sqlInterface getProxy(sqlInterface sql, InvocationHandler sqlProxy) {
sqlInterface proxy = (sqlInterface) Proxy.newProxyInstance(
sql.getClass().getClassLoader(),
sql.getClass().getInterfaces(),
sqlProxy
);

return proxy;
}
}

ProxyTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package ProxyTest;

public class ProxyTest {
public static void main(String[] args) {
sql1 sql = new sql1();
sqlLogHandler logger = new sqlLogHandler(sql);
sqlInterface proxy = sqlProxyGetter.getProxy(sql, logger);
proxy.select();
}
}

/*
output
数据库已连接
log start time [Thu Nov 19 20:38:35 CST 2020]
selected
log end time [Thu Nov 19 20:38:35 CST 2020]
数据库已断开
*/

使用原生的jdk生成代理有两个核心

  • java.lang.reflect.InvocationHandler
  • java.lang.reflect.Proxy

InvocationHandler是一个接口,包含方法invoke,须在对应的调用处理器(这里是sqlLogHandler)进行实现。

Proxy是动态代理的核心类。通过静态方法newProxyInstance来获取动态代理对象。这个方法需要三个参数,一个是接口实现类自己的类加载器,一个是其实现的所有接口,最后是一个调用处理器。

其它方法待后文更新…

Comments