Java动态代理
2022-02-22 17:06:00 # Java

Java动态代理

案例

模拟企业业务功能开发,并完成每个功能的性能统计

需求:

  • 模拟某企业用户管理业务,需包含用户登录,用户删除,用户查询功能,并要统计每个功能的耗时。

分析:

  • 定义一个UserService表示用户业务接口,规定必须完成用户登录,用户删除,用户查询功能。
  • 定义一个实现类UserServiceImpl实现UserService,并完成相关功能,且统计每个功能的耗时。
  • 定义测试类,创建实验类对象,调用方法。

UserService:

1
2
3
4
5
6
7
8
9
10
package CC.Proxy;

/**
* 模拟用户业务功能
*/
public interface UserService {
String login(String loginName,String passWord);
void selectUsers();
boolean deleteUsers();
}

UserviceImpl:

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
49
50
51
package CC.Proxy;

public class UserServiceImpl implements UserService{

@Override
public String login(String loginName, String passWord) {
long startTimer = System.currentTimeMillis();
try {
Thread.sleep(1000);
if("admin".equals(loginName) && "1234".equals(passWord)){
return "success";
}
return "登录名和密码可能有毛病";
} catch (Exception e){
e.printStackTrace();
return "error";
} finally {
long endTimer = System.currentTimeMillis();
System.out.println("login方法耗时: " + (endTimer-startTimer)/1000.0 + "s");
}
}

@Override
public void selectUsers() {
long startTimer = System.currentTimeMillis();
System.out.println("查询了100个用户数据!");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTimer = System.currentTimeMillis();
System.out.println("selectUsers方法耗时: " + (endTimer-startTimer)/1000.0 + "s");
}

@Override
public boolean deleteUsers() {
long startTimer = System.currentTimeMillis();
try {
System.out.println("删除了100个用户数据!");
Thread.sleep(500);
return true;
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}finally {
long endTimer = System.currentTimeMillis();
System.out.println("deleteUsers方法耗时: " + (endTimer-startTimer)/1000.0 + "s");
}
}
}

Test:

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

public class Test {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
System.out.println(userService.login("admin","1234"));
userService.selectUsers();
System.out.println(userService.deleteUsers());
}
}
/**
login方法耗时: 1.011s
success
查询了100个用户数据!
selectUsers方法耗时: 2.007s
删除了100个用户数据!
deleteUsers方法耗时: 0.514s
true
*/

本案例存在哪些问题?

业务对象的每个方法 都要进行性能统计,存在大量重复的代码。

使用动态代理解决问题

动态代理

  • 代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,动态代理就是用来对业务功能(方法)进行代理的 。

关键步骤

  • 必须有接口,实现类要实现接口(代理通常是基于接口实现的)

  • 创建一个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象。

1645524964926.png

1645529622791.png

把这里创立的对象传入代理中,返回一个代理对象回来

ProxyUtil代码:

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
package CC.Proxy;

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

/**
* public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
* 参数一: 类加载器,负责加载代理
* 参数二: 获取被代理对象实现的全部接口。代理要为全部接口的全部方法进行的代理
* 参数三: 代理的核心处理逻辑
*/


public class ProxyUtil {
/**
* 生成业务对象的代理对象
* @param obj
* @return
*/
public static UserService getProxy(UserService obj) {
//返回了一个代理对象
return (UserService) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//参数一: 代理对象本身
//参数二: 正在被代理的方法
//参数三: 被代理方法,应该传入的参数
long startTimer = System.currentTimeMillis();
//马上触发方法的真正执行。(触发真正的业务功能)
Object result = method.invoke(obj,args);

long endTimer = System.currentTimeMillis();
System.out.println(method.getName() + "方法耗时: " + (endTimer-startTimer)/1000.0 + "s");


//把业务功能方法执行的结果返回给调用者
return result;
}
});
}
}

1645529344945.png

最后,在正常逻辑业务中,即可不再重复写性能统计的代码

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
49
50
package CC.Proxy;

public class UserServiceImpl implements UserService{

@Override
public String login(String loginName, String passWord) {

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if("admin".equals(loginName) && "1234".equals(passWord)){
return "success";
}
return "登录名和密码可能有毛病";
}

@Override
public void selectUsers() {
System.out.println("查询了100个用户数据!");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

@Override
public boolean deleteUsers() {
try {
System.out.println("删除了100个用户数据!");
Thread.sleep(500);
return true;
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
}

@Override
public void updateUsers() {
try {
System.out.println("修改了100个用户!");
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

想要增添其他方法的时候,只需写正常的业务逻辑代码,无需再写性能统计的代码。达到动态代理的效果

1645530110238.png