一. JdkProxy
jdkproxy动态代理必须基于接口(interface)实现
- 接口
UserInterface.java
public interface UserService {
String getUserName(String userCde);
}
- 原始实现类:
UseServiceImpl.java
public class UserServiceImpl implements UserSerice {
@Override
public String getUserName(String userCde) {
System.out.println("the name of " + userCde + "is Austin");
return "Austin";
}
}
- 代理类 :
UserProxyFactoryBJdk.java
public class UserProxyFactoryBJdk {
public static UserService getUserServiceProxy(UserService origin) {
UserService userService = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader()
, new Class[]{UserService.class}
, new InvocationHandler() { //动态代理实现类
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object o = method.invoke(origin, args);
System.out.println("after");
return o;
}
});
return userService;
}
public static void main(String[] args) {
UserService userService = getUserServiceProxy(new UserServiceImpl());
userService.getUserName("123");
}
}
执行结果:
before
the name of 123is Austin
after
二. Cglib动态代理
Cglib实现动态代理与JdkProxy不同, 是通过构建继承类实现
- 原始类
UseServiceImpl.java
public class UserServiceImpl implements UserSerice {
@Override
public String getUserName(String userCde) {
System.out.println("the name of " + userCde + "is Austin");
return "Austin";
}
}
- 代理类 :
UserProxyFactoryByCglib.java
public static UserServiceImpl getUserServiceProxy(UserService origin) {
Enhancer enhancer = new Enhancer();
// 设置debug信息
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY
, "/home/aa/dev/testfile/com/austin/meta/cxf/");
// 设置父类:UserServiceImpl
enhancer.setSuperclass(UserServiceImpl.class);
//设置代理实现逻辑
enhancer.setCallback(new CglibInterCeptor() {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("CglibInterCeptor.intercept-before");
Object o = proxy.invokeSuper(obj, args);
System.out.println("CglibInterCeptor.intercept-after");
return o;
}
});
UserServiceImpl userService = ((UserServiceImpl) enhancer.create());
return userService;
}
public static void main(String[] args) {
UserService userService = getUserServiceProxy(new UserServiceImpl());
userService.getUserName("123");
}
- 执行结果
CglibInterCeptor.intercept-before
the name of 123is Austin
CglibInterCeptor.intercept-after
三. Java动态编译
通过JavaCompiler动态编译java源文件,并将相应字节码加载到JVM中,其编译底层通过javac -d 命令进行编译
- 需要动态编译的类文件
package com.austin.meta.dynamiccompiler;
public class UserServiceImplE extends UserServiceImpl {
public UserServiceImplE() {
}
public String getUserName(String userCde) {
System.out.println("before");
super.getUserName(userCde);
System.out.println("after");
return "Austin";
}
}
- 动态编译类
public class JavaCompilerTest {
private static String basePath = "";
public static void main(String[] args) throws Exception{
System.out.println(ClassLoader.getSystemResource(""));
Class<?> userServiceImplE = compiler("UserServiceImplE");
UserServiceImpl o = (UserServiceImpl)userServiceImplE.getConstructor(null).newInstance(null);
o.getUserName("235");
}
private static Class<?> getClass(String pakcge, String className) {
Class<?> clazz = null;
try {
clazz = Class.forName(pakcge + "." +className, true, JavaCompilerTest.class.getClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return clazz;
}
/**
* 动态编译java类,并通加载到JVM
*/
private static Class<?> compiler(String className) throws IOException {
File javaSrcFile = new File(basePath+ "/" + className + ".java");
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, null);
List<String> options = Arrays.asList("-d", ClassLoader.getSystemResource("").toString());
JavaCompiler.CompilationTask task = compiler.getTask(null
, standardFileManager, null, options, null, standardFileManager.getJavaFileObjects(javaSrcFile));
Boolean isCompilerSuccess = task.call();
if(!isCompilerSuccess) {
return null;
}
Class<?> clazz = getClass("com.austin.meta.dynamiccompiler", className);
return clazz;
}
}
- 执行结果
before
the name of 235is Austin
after
四. Javassist动态编译
javassisit可基于原有的类/方法进行修饰增强,其实先原理如下: 在JVM加载类之前通过修改类的内容,并生成字节码后加载到JVM,在使用时则和普通类一致
- 先引入javassist以来
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.27.0-GA</version>
</dependency>
- 原始类
UseServiceImpl.java
public class UserServiceImpl implements UserSerice {
@Override
public String getUserName(String userCde) {
System.out.println("the name of " + userCde + "is Austin");
return "Austin";
}
}
- 实现代理类
public class UserProxyFactoryByJavassist {
public static void getUserServiceProxy() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.austin.meta.jdk.UserServiceImpl");
for (CtMethod ctMethod : cc.getMethods()) {
ctMethod.insertBefore("System.out.println(\"insert before by Javassist\");");
ctMethod.insertAfter("System.out.println(\"insert after by Javassist\");");
}
Class<?> klass = cc.toClass();
System.out.println(klass.getName());
}
public static void main(String[] args) throws Exception {
//在调用之前不能加载UserServiceImpl类,也就是不能获取class,调用静态方法,不能实例化
getUserServiceProxy();
//通过javassist修改对应字节码,可直接new
UserServiceImpl userService = new UserServiceImpl();
userService.getUserName("123");
}
}
- 执行结果
com.austin.meta.jdk.UserServiceImpl
insert before by Javassist
the name of 123is Austin
insert after by Javassist
五. ASM
ASM是通过修改字节码来实现动态修改class, 其主要元素包括在ASM中元素(被访问者)ClassReader、MethodNode等,访问者接口包含ClassVisitor、AnnotationVisitor、FieldVisitor、MethodVisitor
具体可参考官网