栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java:使用javassist模拟实现cglib代理操作

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java:使用javassist模拟实现cglib代理操作

当前版本:jdk1.8

1. 声明

当前内容主要为使用javassist实现cglib的代理功能,当前javassist内容参考官方文档官方文档

主要核心思想:

    使用javassist动态创建需要操作类的子类在子类中重写方法并构建需要转移的InvocationHandler和方法调用这里直接使用java.lang.reflect.InvocationHandler来实现转移操作
2. 基本demo
public class JavassistTest {
	public interface IShow{
		void show();
	}
	public static class Father implements IShow{
		public void show() {
			System.out.println("father");
			//return "show called";
		}
		
		public String getResult() {
			return "ok";
		}
		
	}
	public static void main(String[] args) throws Exception {
		Object target = new Father();
		Father proxy = (Father)generatorProxy(Father.class,new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				System.out.println("before===>");
				Object invoke = method.invoke(target, args);
				System.out.println("after===>");
				return invoke;
			}
		});
		((IShow)proxy).show();
		String result = proxy.getResult();
		System.out.println(result);
		System.out.println(proxy);
	}
	
	// 生成代理(只处理实体类的情况)
	private static Object generatorProxy(Class clazz,InvocationHandler invocationHandler) throws Exception {
		ClassPool pool = ClassPool.getDefault();
		CtClass fatherClass = pool.get(clazz.getName());
		CtClass invocationhandlerClass = pool.get(InvocationHandler.class.getName());
		//	直接创建一个子类
		CtClass childClass = pool.makeClass("com.hy.java.bytecode.generator.Proxy$1", fatherClass);
		
		// 为其添加所有的接口
		generatorInterfaces(childClass,clazz,pool);
		//	为该子类添加一个invocationHandler的字段
		generatorField(childClass);
		//	添加有参数的构造函数
		generatorConstructor(invocationhandlerClass,childClass);
		
		// 生成类的所有方法重写,并完成执行转发操作
		List generatorMethods = generatorMethod(clazz,childClass);
		for (CtMethod ctMethod : generatorMethods) {
			childClass.addMethod(ctMethod);
		}

		Class generatorClass = childClass.toClass();
		Constructor argConstructor = generatorClass.getConstructor(InvocationHandler.class);
		Object newInstance = argConstructor.newInstance(new Object[] {invocationHandler});
		return newInstance;
	}
	
	// 为生成的类添加接口
	private static void generatorInterfaces(CtClass childClass,Class clazz,ClassPool pool) throws NotFoundException {
		Class[] interfaces = clazz.getInterfaces();
		for (Class in : interfaces) {
			CtClass ctClass = pool.get(in.getName());
			childClass.addInterface(ctClass);
		}
	}
	
	// 为生成的类添加有参的构造函数,并调用赋值
	private static void generatorConstructor(CtClass invocationhandlerClass,CtClass childClass) throws CannotCompileException {
		CtConstructor constructor = new CtConstructor(new CtClass[] {invocationhandlerClass}, childClass);
		// 执行this.h = 第一个参数,就是给创建的类进行赋值操作
		constructor.setBody("$0.h=$1;");
		childClass.addConstructor(constructor);
	}
	
	// 为当前的类定义一个字段
	private static void generatorField(CtClass childClass) throws CannotCompileException {
		CtField hField = CtField.make("public java.lang.reflect.InvocationHandler h;", childClass);
		childClass.addField(hField);
		
	}
	
	// 为实体类创建代理方法,为所有的方法都实现代理操作
	private static List generatorMethod(Class clazz,CtClass childClass) throws CannotCompileException {
		// 实现所有的clazz中的所有方法
		Method[] declaredMethods = clazz.getDeclaredMethods();
		List ctMethods =new ArrayList<>(declaredMethods.length);
		for (Method method : declaredMethods) {
			String name = method.getName();
			Class returnType = method.getReturnType();
			Class[] parameterTypes = method.getParameterTypes();
			List> asList = Arrays.asList(parameterTypes);
			String parameterName = getParameterName(asList);
			CtMethod ctMethod = CtMethod.make("public "+returnType.getName()+" "+name+"("+parameterName+");", childClass) ;
			if(returnType==Void.class) {
				//clazz.getMethod("equals", parameterTypes)
				ctMethod.setBody("{($r)$0.h.invoke($0,"+clazz.getName()+".class.getMethod(""+name+"",$sig),$args);}");
			}else {
				// return this.h.invoke(this,method,args);
				ctMethod.setBody("{return ($r)$0.h.invoke($0,"+clazz.getName()+".class.getMethod(""+name+"",$sig),$args);}");
			}
			ctMethods.add(ctMethod);
			
		}
		return ctMethods;
		
	}
	
	// 生成参数列表
	private static String getParameterName(List> asList) {
		if(asList.isEmpty()) {
			return "";
		}
		int size = asList.size();
		StringBuilder stringBuilder = new StringBuilder();
		for (int i = 0; i < size; i++) {
			String name = asList.get(i).getName();
			stringBuilder.append(name);
			if(i 

这里我们构造一个类这个类继承传递的类,并实现传递类的接口,具有以下功能

    具有有参的构造函数,参数为InvocationHandler,并在构造函数内为字段h赋值具有一个字段InvocationHandler h所有的方法都直接通过调用h的方式进行调用转发的操作

缺点:只能代理实体类

3. 测试和总结


实现成功!!!

1. 其中最主要的部分为($r)表示使用来将invoke的结果Object进行强制转换为返回值类型,保证结果(主要是为了解决有返回值的方法调用问题)

2. 对于方法的创建必须要手动进行访问修饰符以及方法参数的构建操作,这个比较麻烦

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/755702.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号