Java中实现动态代理5种实现

一. JdkProxy

jdkproxy动态代理必须基于接口(interface)实现

  1. 接口UserInterface.java
public interface UserService {
	String getUserName(String userCde);
}
  1. 原始实现类:UseServiceImpl.java
public class UserServiceImpl implements UserSerice {
	@Override
	public String getUserName(String userCde) {
		System.out.println("the name of " + userCde + "is Austin");
        return "Austin";
	}
}
  1. 代理类 :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不同, 是通过构建继承类实现

  1. 原始类UseServiceImpl.java
public class UserServiceImpl implements UserSerice {
	@Override
	public String getUserName(String userCde) {
		System.out.println("the name of " + userCde + "is Austin");
        return "Austin";
	}
}
  1. 代理类 :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");
    }
  1. 执行结果
    CglibInterCeptor.intercept-before
    the name of 123is Austin
    CglibInterCeptor.intercept-after

三. Java动态编译

通过JavaCompiler动态编译java源文件,并将相应字节码加载到JVM中,其编译底层通过javac -d 命令进行编译

  1. 需要动态编译的类文件
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";
    }
}
  1. 动态编译类
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;
    }
}

  1. 执行结果
    before
    the name of 235is Austin
    after

四. Javassist动态编译

javassisit可基于原有的类/方法进行修饰增强,其实先原理如下: 在JVM加载类之前通过修改类的内容,并生成字节码后加载到JVM,在使用时则和普通类一致

  1. 先引入javassist以来
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.27.0-GA</version>
</dependency>
  1. 原始类UseServiceImpl.java
public class UserServiceImpl implements UserSerice {
	@Override
	public String getUserName(String userCde) {
		System.out.println("the name of " + userCde + "is Austin");
        return "Austin";
	}
}
  1. 实现代理类
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");
    }
}
  1. 执行结果
    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
具体可参考官网

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值