友情支持
如果您觉得这个笔记对您有所帮助,看在D瓜哥码这么多字的辛苦上,请友情支持一下,D瓜哥感激不尽,😜
有些打赏的朋友希望可以加个好友,欢迎关注D 瓜哥的微信公众号,这样就可以通过公众号的回复直接给我发信息。
公众号的微信号是: jikerizhi 。因为众所周知的原因,有时图片加载不出来。 如果图片加载不出来可以直接通过搜索微信号来查找我的公众号。 |
4. 代理模式 与 AOP
4.1. 定义
- 代理模式(Proxy)
为其他对象提供一种代理以控制这个对象的访问。
《设计模式》
4.3. 静态代理模式
1
2
3
4
5
6
7
8
9
10
11
package com.diguage.didp.proxy;
/**
* Subject类,定义了 {@link RealSubject} 和 {@link Proxy} 的共用接口。
*
* @author D瓜哥, https://www.diguage.com/
* @since 2017-05-16
*/
public interface Subject {
void request();
}
RealSubject类,定义Proxy所代表的真实实体。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.diguage.didp.proxy;
/**
* RealSubject 类
*
* @author D瓜哥, https://www.diguage.com/
* @since 2017-05-16
*/
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("真是请求!");
}
}
Proxy类,保存一个引用使得代理可以访问实体,并提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.diguage.didp.proxy;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2017-05-16
*/
public class Proxy implements Subject {
private Subject realSubject;
public Proxy(Subject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
System.out.println("使用代理开始请求…");
realSubject.request();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.diguage.didp.proxy;
/**
* Client 类
*
* @author D瓜哥, https://www.diguage.com/
* @since 2017-05-16
*/
public class Client {
public static void main(String[] args) {
Subject subject = new Proxy(new RealSubject());
subject.request();
}
}
4.3.1. 再来一个例子…
1
2
3
4
5
6
7
8
9
10
11
package com.diguage.didp.proxy;
/**
* 用户接口
*
* @author D瓜哥, https://www.diguage.com/
* @since 16/11/2016.
*/
public interface UserService {
String getById(int id);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.diguage.didp.proxy;
import java.util.concurrent.TimeUnit;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 16/11/2016.
*/
public class UserServiceImpl implements UserService {
@Override
public String getById(int id) {
try {
System.out.println("真是请求:根据ID获取对应用户…");
TimeUnit.MILLISECONDS.sleep(id);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "User-" + id;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.diguage.didp.proxy;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 16/11/2016.
*/
public class UserServiceAuthenticationProxy implements UserService {
UserService userService;
public UserServiceAuthenticationProxy(UserService userService) {
this.userService = userService;
}
@Override
public String getById(int id) {
if (id < 1000) {
System.out.println("非特权用户,禁止访问……");
return null;
}
return userService.getById(id);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.diguage.didp.proxy;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 16/11/2016.
*/
public class UserServiceProxyMain {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserService proxy = new UserServiceAuthenticationProxy(userService);
System.out.println(proxy.getById(123));
}
}
请思考: 到现在为止,你们发现什么问题了吗? 代理模式这样实现有什么问题吗?还有其他改进空间吗?? |
4.4. 动态代理
先看一个图,看看方法调用的:
Java 是面向对象,那么 Java 如何对 Java 中 package
、 class
、 方法等如何建模呢?
我们可以从上图的流程中可以横切一刀,如下图:
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
package com.diguage.didp.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2016-11-16
*/
public class ProfilerInvocationHandler implements InvocationHandler {
private Object realObject;
public ProfilerInvocationHandler(Object realObject) {
this.realObject = realObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.printf("Profiler======\n%s\n", method.getName());
long start = System.currentTimeMillis();
Object result = method.invoke(realObject, args);
long time = System.currentTimeMillis() - start;
System.out.println("耗时: " + time);
System.out.println("Profiler======");
return result;
}
}
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
package com.diguage.didp.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2018-03-16
*/
public class LoggerInvocationHandler implements InvocationHandler {
private Object realObject;
public LoggerInvocationHandler(Object realObject) {
this.realObject = realObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.printf("Logger------\nMethod: %s\n", method.getName());
if (args != null && args.length > 0) {
System.out.println("Params:");
for (Object arg : args) {
System.out.println(arg);
}
}
Object result = method.invoke(realObject, args);
System.out.println("Logger------");
return result;
}
}
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 com.diguage.didp.proxy;
import java.lang.reflect.Proxy;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 16/11/2016.
*/
public class UserServiceDynamicProxyMain {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
ClassLoader classLoader = UserService.class.getClassLoader();
Class<?>[] interfaces = UserServiceImpl.class.getInterfaces();
UserService profilerInstance =
(UserService)
Proxy.newProxyInstance(
classLoader,
interfaces,
new ProfilerInvocationHandler(userService));
UserService logProfilerInstance =
(UserService)
Proxy.newProxyInstance(
classLoader,
interfaces,
new LoggerInvocationHandler(profilerInstance));
System.out.println("最终结果:" + logProfilerInstance.getById(345));
Subject subject = (Subject) Proxy.newProxyInstance(
RealSubject.class.getClassLoader(),
RealSubject.class.getInterfaces(),
new LoggerInvocationHandler(new RealSubject()));
subject.request();
}
// public static <T> T newProxyInstance(ClassLoader classLoader,
// InvocationHandler handler, T... t) {
// return (T) Proxy.newProxyInstance(classLoader, t.getClass(), handler);
// }
}
流程与这个类似这样的,还有 Java Web 中的 Filter
, Spring MVC 中的 ``
请思考: 代理模式这样实现有什么问题吗?还有其他改进空间吗?? |
4.5. 来个黑魔法…
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
package com.diguage.didp.proxy.asm;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2016-11-17 23:19
*/
public class Account {
public int operation() {
System.out.println("operation……");
int timeout = new Random().nextInt(1000);
try {
TimeUnit.MILLISECONDS.sleep(timeout + 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return timeout;
}
public String getById(int id) {
System.out.println("getById……");
try {
// 以参数传递过来的数字来决定休眠时间,
// 来检验实际效果
TimeUnit.MILLISECONDS.sleep(id);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Account-" + id;
}
public static void main(String[] args) {
Account account = new Account();
account.operation();
account.getById(123);
}
}
我们来看一下,编译后生成的文件……
cd /Users/diguage/Documents/wiki.diguage.com/java/deep-in-design-patterns/target/classes/com/diguage/didp/proxy/asm
vim /Users/diguage/Documents/wiki.diguage.com/java/deep-in-design-patterns/target/classes/com/diguage/didp/proxy/asm/Account.class
:%!xxd
javap -v /Users/diguage/Documents/wiki.diguage.com/java/deep-in-design-patterns/target/classes/com/diguage/didp/proxy/asm/Account.class
Java 虚拟机规范中,对 Java Class 文件格式的定义: Chapter 4. The class File Format
Java 虚拟机规范中,对 Java 方法表格式的定义: Chapter 4. The class File Format
时间统计类……
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.diguage.didp.proxy.asm;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2016-11-17 23:22
*/
public class Profiler {
static ThreadLocal<Long> t = new ThreadLocal<Long>();
public static void start() {
t.set(System.currentTimeMillis());
}
public static void end() {
long time = System.currentTimeMillis() - t.get();
System.out.print(Thread.currentThread().getStackTrace()[2] + " speed:");
System.out.println(time);
}
}
修改字节码,在每个方法的开始部分和返回部分来插入我们的时间统计代码……
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
package com.diguage.didp.proxy.asm;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2016-11-18 10:15
*/
public class ProfilerMethodAdapter extends MethodVisitor implements Opcodes {
public ProfilerMethodAdapter(MethodVisitor mv) {
super(Opcodes.ASM5, mv);
}
@Override
public void visitCode() {
visitMethodInsn(Opcodes.INVOKESTATIC, "com/diguage/didp/proxy/asm/Profiler", "start", "()V");
super.visitCode();
}
@Override
public void visitInsn(int opcode) {
if (opcode >= IRETURN && opcode <= RETURN) {
visitMethodInsn(Opcodes.INVOKESTATIC, "com/diguage/didp/proxy/asm/Profiler", "end", "()V");
}
mv.visitInsn(opcode);
}
}
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
package com.diguage.didp.proxy.asm;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2016-11-18 10:15
*/
public class ProfilerClassAdapter extends ClassVisitor {
public ProfilerClassAdapter(ClassVisitor cv) {
super(Opcodes.ASM5, cv);
}
@Override
public MethodVisitor visitMethod(
final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
MethodVisitor wrapperMv = mv;
if (mv != null) {
// TODO 如何实现只编制指定类下的方法呢?
// if (name.equals("operation")) {
wrapperMv = new ProfilerMethodAdapter(mv);
// }
}
return wrapperMv;
}
}
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
package com.diguage.didp.proxy.asm;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2016-11-17 23:26
*/
public class ProfilerWeaveMain {
public static void main(String[] args) throws IOException, URISyntaxException {
System.out.println("开始修改字节码…");
// 如何实现编制指点类?通过配置文件来获得!
String className = Account.class.getName();
ClassReader cr = new ClassReader(className);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
ProfilerClassAdapter classAdapter = new ProfilerClassAdapter(cw);
cr.accept(classAdapter, ClassReader.SKIP_DEBUG);
byte[] data = cw.toByteArray();
URL url =
Account.class.getClassLoader().getResource(className.replaceAll("\\.", "/") + ".class");
// System.out.println(url);
// System.out.println(
// "file:/Users/diguage/Documents/wiki.diguage.com/java/deep-in-design-patterns/target/classes/com/diguage/didp/proxy/asm/Account.class");
// // File file = new File(url.replaceFirst("file:/", "file:///"));
File file = new File(url.toURI());
// System.out.println(file.exists());
// if (!file.exists()) {
// System.out.println("Create:" + file.createNewFile());
// }
// System.out.println(file.isFile());
// System.out.println(file.canWrite());
FileOutputStream fout = new FileOutputStream(file);
fout.write(data);
fout.close();
System.out.println("字节码修改完毕。");
}
}
再来运行一下看看…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.diguage.didp.proxy.asm;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2016-11-17 23:47
*/
public class AfterWeaveProfilerMain {
public static void main(String[] args) {
Account account = new Account();
System.out.println(account.operation());
// 可以通过传递不同的数字来观察耗时统计,
// 来检验是否修改过字节码……
System.out.println(account.getById(4000));
System.out.println(account.toString());
}
}
在使用 ASM 生成代理 class 文件时,发现确定类文件的路径是个大问题。这里需要注意的是针对 file 的 URL 格式规范。 |
请思考: 代理模式这样实现有什么问题吗?还有其他改进空间吗?? |
4.7. ClassLoader
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package com.diguage.didp.proxy.loader;
import com.diguage.didp.proxy.asm.ProfilerClassAdapter;
import com.diguage.didp.proxy.bytebuddy.ProfilerInterceptor;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.pool.TypePool;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2018-03-23
*/
public class ProxyClassLoader extends ClassLoader {
public ProxyClassLoader(ClassLoader parent) {
super(parent);
}
/**
* @param className 全限定名的类目, 例如 com.diguage.Foo
*/
private Class getClass(String className) throws ClassNotFoundException {
String file = className.replace('.', File.separatorChar) + ".class";
byte[] classByteArray = null;
try {
// TODO 在这里做手脚
// ClassReader cr = new ClassReader(className);
// ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
// ProfilerClassAdapter classAdapter = new ProfilerClassAdapter(cw);
// cr.accept(classAdapter, ClassReader.SKIP_DEBUG);
// classByteArray = cw.toByteArray();
ClassFileLocator classFileLocator = ClassFileLocator.ForClassLoader.of(Thread.currentThread().getContextClassLoader());
TypePool typePool = TypePool.Default.ofSystemLoader();
//
classByteArray = new ByteBuddy()
.rebase(typePool.describe(className).resolve(), classFileLocator)
.method(ElementMatchers.any())
.intercept(MethodDelegation.to(ProfilerInterceptor.class))
.make()
.getBytes();
// Class<? extends DynamicType.Unloaded> clazz = new ByteBuddy()
// .rebase()
// .rebase(Object.class)
// .method(ElementMatchers.any())
// .intercept(MethodDelegation.to(ProfilerInterceptor.class))
// .make().getClass();
Class clazz = defineClass(className, classByteArray, 0, classByteArray.length);
resolveClass(clazz);
return clazz;
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
/**
* @param name 全限定名的类名
*/
@Override
public Class loadClass(String name) throws ClassNotFoundException {
System.out.println("Loading Class '" + name + "'");
if (name.startsWith("com.diguage.didp.proxy.asm.Account") && !name.contains("$")) {
System.out.println("Loading Class using ProxyClassLoader");
return getClass(name);
}
return super.loadClass(name);
}
/**
* @param name 全限定名的类名
* @return 文件的字节数组
* @throws IOException
*/
private byte[] loadClassFileData(String name) throws IOException {
InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(name);
int size = stream.available();
byte buff[] = new byte[size];
DataInputStream in = new DataInputStream(stream);
in.readFully(buff);
in.close();
return buff;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.diguage.didp.proxy.loader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ClassLoaderMain {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
String progClass = "com.diguage.didp.proxy.asm.Account";
ProxyClassLoader classLoader = new ProxyClassLoader(Thread.currentThread().getContextClassLoader());
Class clazz = classLoader.loadClass(progClass);
Object instance = clazz.newInstance();
Method operation = clazz.getMethod("operation");
operation.invoke(instance);
Method getById = clazz.getMethod("getById", int.class);
getById.invoke(instance, 123);
}
}
请思考: 代理模式这样实现有什么问题吗?还有其他改进空间吗?? |
4.8. 可不可更透明点…
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 com.diguage.didp.proxy.agent;
import com.diguage.didp.proxy.asm.ProfilerClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2016-11-18 10:21
*/
public class PreMainAddTimeStatAgent {
public static void premain(String agentArgs, Instrumentation instrumentation) {
System.out.println("agentArgs: " + agentArgs);
instrumentation.addTransformer(
new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (className.equals("com/diguage/didp/proxy/asm/Account")) {
System.out.println("meet com.diguage.didp.proxy.asm.Account");
ClassReader cr = new ClassReader(classfileBuffer);
ClassWriter cw =
new ClassWriter(
(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES));
ProfilerClassAdapter classAdapter = new ProfilerClassAdapter(cw);
cr.accept(classAdapter, ClassReader.SKIP_DEBUG);
return cw.toByteArray();
} else {
System.out.println("\nload: " + className);
return classfileBuffer;
}
}
}
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.diguage.didp.proxy.agent;
import com.diguage.didp.proxy.asm.Account;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2016-11-18 14:41
*/
public class RunAccountMain {
public static void main(String[] args) {
Account account = new Account();
System.out.println(account.getById(789));
System.out.println(account.operation());
}
}
# 运行
java -cp .:/Users/diguage/develop/tools/MavenRepository/org/ow2/asm/asm-all/5.2/asm-all-5.2.jar -javaagent:target/deep-in-design-patterns-0.0.1.jar com.diguage.didp.proxy.agent.RunAccountMain
java -cp .:/Users/diguage/develop/tools/MavenRepository/net/bytebuddy/byte-buddy/1.8.0/byte-buddy-1.8.0.jar -javaagent:target/deep-in-design-patterns-0.0.1.jar com.diguage.didp.proxy.agent.RunAccountMain
请思考: 代理模式这样实现有什么问题吗?还有其他改进空间吗?应用上线后怎么搞? |
4.9. 来点通俗易懂的…
用 Byte Buddy 来搞…
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.diguage.didp.proxy.bytebuddy;
import net.bytebuddy.asm.Advice;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2018-03-15
*/
public class ProfilerAnnotationInterceptor {
public static ThreadLocal<Long> threadLocal = new ThreadLocal();
@Advice.OnMethodEnter
public static void enter(@Advice.Origin("#t.#m") String signature) {
System.out.printf("Enter: %s\n", signature);
long start = System.currentTimeMillis();
threadLocal.set(start);
}
@Advice.OnMethodExit
public static void exit(@Advice.Origin("#t.#m") String signature) {
long value = System.currentTimeMillis() - threadLocal.get();
System.out.printf("Exit: %s\nTime: %d\n\n", signature, value);
}
}
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
package com.diguage.didp.proxy.bytebuddy;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.instrument.Instrumentation;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2018-03-15 19:17:38
*/
public class ProflierAnnotationAgent {
public static void premain(String agentArgs, Instrumentation instrumentation) {
System.out.println("Premain started");
try {
new AgentBuilder.Default()
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut()) // Debug
.with(AgentBuilder.TypeStrategy.Default.REBASE)
// .type((typeDescription, classLoader, javaModule, aClass, protectionDomain) -> true)
.type(ElementMatchers.any())
.transform((builder, typeDescription, classLoader, javaModule) ->
builder.visit(Advice.to(ProfilerAnnotationInterceptor.class).on(ElementMatchers.any())))
.installOn(instrumentation);
} catch (RuntimeException e) {
System.out.println("Exception instrumenting code : " + e);
e.printStackTrace();
}
}
}
4.9.1. 再来一组更简单的…
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
package com.diguage.didp.proxy.bytebuddy;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2018-03-16
*/
public class ProfilerInterceptor {
@RuntimeType
public static Object intercept(@Origin Method method,
@SuperCall Callable<?> callable) {
long start = System.currentTimeMillis();
try {
return callable.call();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage(), e);
} finally {
System.out.println(method + " took " + (System.currentTimeMillis() - start) + "\n\n");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.diguage.didp.proxy.bytebuddy;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.instrument.Instrumentation;
/**
* @author D瓜哥, https://www.diguage.com/
* @since 2018-03-16
*/
public class ProflierAgent {
public static void premain(String arguments,
Instrumentation instrumentation) {
new AgentBuilder.Default()
.type(ElementMatchers.any())
.transform((builder, type, classLoader, module) ->
builder.method(ElementMatchers.any())
.intercept(MethodDelegation.to(ProfilerInterceptor.class))
).installOn(instrumentation);
}
}
请思考: 代理模式这样实现有什么问题吗?还有其他改进空间吗?? |