jdk(只针对有接口的)
1 public class JdkProxy implements InvocationHandler { 2 3 private Object real; 4 5 private Class interfaceClass; 6 7 public JdkProxy(Object real, Class interfaceClass) throws Exception { 8 if(real==null&&interfaceClass==null){ 9 throw new Exception("不允许同时为空!"); 10 } 11 if(real!=null){ 12 this.real = real; 13 } else { 14 this.interfaceClass = interfaceClass; 15 } 16 } 17 18 //所有方法的增强操作 19 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 20 //System.out.println("内存代理类proxy"+proxy);//出现java.lang.StackOverflowError栈深度溢出,会调proxy.toString()方法 21 System.out.println("invoke start:"+method.getName()); 22 Object result; 23 if(real!=null){ 24 result = method.invoke(real, args); 25 } else { 26 //只传过来一个接口,这个地方的逻辑想怎么写都行的 27 result = "不代理具体的对象,只要实现接口就行了,这里写实现接口的方法"; 28 } 29 System.out.println("invoke end:"+method.getName()); 30 return result; 31 } 32 33 //定义获取代理对象方法 34 public Object getJDKProxy(){ 35 if(real!=null){ 36 return Proxy.newProxyInstance(real.getClass().getClassLoader(), real.getClass().getInterfaces(), this); 37 } else { 38 return Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, this); 39 } 40 } 41 42 /** 43 * 保存class文件 44 * @param clazz class对象 45 * @param proxyName 代理类的名字,可随意指定 46 */ 47 public void saveClassFile(Class clazz,String proxyName) { 48 //生成class的字节数组,此处生成的class与proxy.newProxyInstance中生成的class除了代理类的名字不同,其它内容完全一致 49 byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces()); 50 FileOutputStream fos = null; 51 try { 52 fos = new FileOutputStream("C:\\class\\" + proxyName + ".class"); 53 fos.write(classFile);//保存到磁盘 54 fos.flush(); 55 }catch(Exception e) { 56 e.printStackTrace(); 57 }finally { 58 try { 59 fos.close(); 60 }catch(IOException e) { 61 e.printStackTrace(); 62 } 63 } 64 } 65 66 interface UserService { 67 void doSomething(); 68 } 69 70 static final class UserServiceImpl implements UserService { 71 public final void doSomething() { 72 System.out.println("真实对象的方法执行过程..."); 73 } 74 } 75 76 public static void main(String[] args) throws Exception { 77 //System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); //设置系统属性 78 //JdkProxy jdkProxy = new JdkProxy(new UserServiceImpl(), null); 79 JdkProxy jdkProxy = new JdkProxy(null, UserService.class); 80 Object proxy = jdkProxy.getJDKProxy(); 81 ((UserService)proxy).doSomething(); 82 jdkProxy.saveClassFile(proxy.getClass(), "proxyName"); 83 } 84 }
核心原理:

1.在内存中生成新对象,新对象中持有invocationHandler对象,实现了原接口,继承父类Proxy
2.新内存对象实现原接口的方法,内部直接调用invocationHandler.invoke()方法,因为invocationHandler中持有原接口的真实对象,相当于间接调用了真实对象
3.重写了equals、hashCode、toString
4.注意如果在invocationHandler.invoke()方法中要用代理类proxy来调用任何方法,都会出现递归循环调用,出现java.lang.StackOverflowError栈深度溢出
5.可以没有真实对象,只有接口类,在内存中生成实现接口的对象,依赖invocationHandler对象来自定义接口方法的具体实现;mybatis中,根据接口mapper,生成mapper对象就是利用这个功能
cglib(针对没有接口的),原有类不能有父类,非final修饰的类和方法
1 public class CglibProxy implements MethodInterceptor { 2 3 private Class clazz; 4 5 private boolean isInterface; 6 7 public CglibProxy(Class clazz){ 8 isInterface = clazz.isInterface(); 9 this.clazz = clazz; 10 } 11 12 //所有方法的增强拦截操作 13 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 14 //System.out.println("内存代理类obj"+obj);//出现java.lang.StackOverflowError栈深度溢出 15 System.out.println("Cglib动态代理,监听开始:"+method.getName()); 16 Object result; 17 if(!isInterface){ 18 result = proxy.invokeSuper(obj, args);//调用父类的方法执行 19 } else { 20 //只传过来一个接口,这个地方的逻辑想怎么写都行的 21 result = "只要实现接口就行了,这里写实现接口的方法"; 22 } 23 System.out.println("Cglib动态代理,监听结束:"+method.getName()); 24 return result; 25 } 26 27 //定义获取代理对象方法 28 public Object getCglibProxy(){ 29 //为目标对象target赋值 30 Enhancer enhancer = new Enhancer(); 31 //设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类 32 enhancer.setSuperclass(clazz); 33 enhancer.setCallback(this);// 设置回调 34 /*enhancer.setCallbackFilter(new CallbackFilter() { 35 public int accept(Method method) { 36 return 0; 37 } 38 }); 39 enhancer.setCallback(new LazyLoader() { 40 public Object loadObject() throws Exception { 41 return null; 42 } 43 }); 44 enhancer.setCallback(new Dispatcher() { 45 public Object loadObject() throws Exception { 46 return null; 47 } 48 }); 49 enhancer.setCallback(new ProxyRefDispatcher() { 50 public Object loadObject(Object o) throws Exception { 51 return null; 52 } 53 }); 54 enhancer.setCallback(new FixedValue() { 55 public Object loadObject() throws Exception { 56 return "FixedValue"; 57 } 58 }); 59 enhancer.setCallback(NoOp.INSTANCE);//NoOp回调把对方法调用直接委派到这个方法在父类中的实现(也可以理解成真实对象直接调用方法); 60 Callback callbacks[] = new Callback[] {this, NoOp.INSTANCE}; 61 enhancer.setCallbacks(callbacks);*/ 62 //setCallbacks配合CallbackFilter一起使用 63 enhancer.setCallbackFilter(new CallbackFilter() { 64 public int accept(Method method) { 65 return 0; 66 } 67 }); 68 Object result = enhancer.create();//创建并返回代理对象 69 return result; 70 } 71 72 interface UserService { 73 void doSomething(); 74 } 75 76 static class UserServiceImpl implements UserService{ 77 public void doSomething() { 78 System.out.println("真实类的方法执行过程..."); 79 } 80 } 81 82 public static void main(String[] args) { 83 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\class"); 84 //CglibProxy cglibProxy = new CglibProxy(UserServiceImpl.class); 85 CglibProxy cglibProxy = new CglibProxy(UserService.class); 86 Object proxy = cglibProxy.getCglibProxy(); 87 ((UserService)proxy).doSomething(); 88 } 89 }
核心原理:
1.根据原有类,内存中生成其子类,重写所有方法
2.因为增加了一个callback接口,在Enhancer生成子类的时候,更加灵活,可以多个setCallbacks配合setCallbackFilter,不同的callback可以实现不同的增强功能
3.原有类可以是一个接口,依靠MethodInterceptor对象生成具体接口方法的实现,mybatis中,根据接口mapper,生成mapper对象也可以利用这个实现