jdk动态代理为什么只能实现接口-jdk动态代理为什么必须有接口( 二 )


从上面看,生成的动态代理类已经 继承了extends Proxy,所以jdk动态代理只能实现接口 。
怎样手写动态代理1、自定义类加载器
自定义类加载器,加载磁盘上生成的class文件,代码如下:
/** * 自定义classLoader,加载外部class文件 */public class YjClassLoader extends ClassLoader {private File classPathFile;public YjClassLoader( ) {String classPath = YjClassLoader.class.getResource("").getPath();this.classPathFile = new File(classPath);}@Overrideprotected Class findClass( String name ) throws ClassNotFoundException {String className = YjClassLoader.class.getPackage().getName() + "." + name;if (Objects.nonNull(classPathFile)) {File classFile = new File(classPathFile, name.replaceAll("\.", "/") + ".class");if (classFile.exists()) {FileInputStream in = null;ByteArrayOutputStream out = null;try {in = new FileInputStream(classFile);out = new ByteArrayOutputStream();byte[] b = new byte[1024];int len = 0;while ((len = in.read(b)) != -1) {out.write(b, 0, len);}return defineClass(className, out.toByteArray(), 0, out.size());} catch (Exception e) {} finally {if (in != null) {try {in.close();} catch (IOException e) {e.printStackTrace();}}if (out != null) {try {out.close();} catch (IOException e) {e.printStackTrace();}}}}}return null;}}
2、实现InvocationHandler接口
public interface YjInvocationHandler {Object invoke( Object proxy, Method method, Object[] args) throws Throwable;}
3、代理Proxy类
public class YjProxy {private static final String LINE_BREAK = "rn";public static Object newProxyInstance(YjClassLoader classLoader,Class [] interfaces,YjInvocationHandler h) {try {//1.動態生成java文件String src = https://www.goobye.net/generateSrc(interfaces);System.out.println(src);//2.java 文件輸出到磁盤上String filePath = YjProxy.class.getResource("").getPath();File file = new File(filePath+"$Proxy0.java");FileWriter fw = new FileWriter(file);fw.write(src);fw.flush();fw.close();//3.把生成的文件編譯成class文件JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);Iterable iterable = manage.getJavaFileObjects(file);JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);task.call();manage.close();//4.加載到JVM中Class proxyClass =classLoader.findClass("$Proxy0");Constructor c = proxyClass.getConstructor(YjInvocationHandler.class);file.delete();//5、返回字节码重组以后的新的代理对象return c.newInstance(h);}catch (Exception e){}return null;}private static String generateSrc(Class[] interfaces){StringBuffer sb = new StringBuffer();sb.append("package com.wy.study.proxy;" + LINE_BREAK);sb.append("import java.lang.reflect.Method;" + LINE_BREAK);sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + LINE_BREAK);sb.append("YjInvocationHandler h;" + LINE_BREAK);sb.append("public $Proxy0(YjInvocationHandler h) { " + LINE_BREAK);sb.append("this.h = h;");sb.append("}" + LINE_BREAK);for (Method m : interfaces[0].getMethods()){sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + LINE_BREAK);sb.append("try{" + LINE_BREAK);sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod("" + m.getName() + "",new Class[]{});" + LINE_BREAK);sb.append("this.h.invoke(this,m,null);" + LINE_BREAK);sb.append("}catch(Throwable e){" + LINE_BREAK);sb.append("e.printStackTrace();" + LINE_BREAK);sb.append("}");sb.append("}");}sb.append("}" + LINE_BREAK);return sb.toString();} }
实现步骤如下:
(1) 生成java文件,模仿JDK生成的$proxy0类
需要实现传入的几接口,并且需要InvocationHandler注入里面去,然后循环接口中的所有方法,生成代理 :
(2) 把生成的文件输出到磁盘中
(3) 把生成的文件编译成class文件
(4) 把编译好的class文件加载到JVM中
【jdk动态代理为什么只能实现接口-jdk动态代理为什么必须有接口】

4、测试
(1) 代理类
public class TransactionProxy implements YjInvocationHandler{private Object target;publicTransactionProxy(Object target){this.target = target;}@Overridepublic Object invoke( Object proxy, Method method, Object[] args ) throws Throwable {try {System.out.println("開始事務.................");method.invoke(this.target,args);}catch (Exception e){System.out.println("回滾事務..............");}finally {System.out.println("提交事務..............");}return null;}}
测试类:
public class TestProxy{public static void main( String[] args ) {UserServiceImpl userService = new UserServiceImpl();IUserService proxyUserService = (IUserService) YjProxy.newProxyInstance(new YjClassLoader(),userService.getClass().getInterfaces(),new TransactionProxy(userService));System.out.println(proxyUserService);proxyUserService.saveUser();}}
测试结果: