JDK原生动态代理
http://www.cnblogs.com/xiaoluo501395377/p/3383130.html
面向接口编程就一定要先定义接口再定义实现类吗?一个项目中有大量的 dao/imp、service/imp 包,看上去很‘规范’(理由是大家都这么写)。其实这样写是有历史包袱的,AOP特性的实现依赖于动态代理机制,而最早的框架中只能对接口进行动态代理,这样就导致每次都是先写接口,然后让框架去代理这个接口的实现类,返回对象是接口。而现在框架有能力直接代理对象无须接口,那我们的dao、service接口还有保留的意义吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
public class DynamicProxyTest { interface Animal { void say();
void say(String words); }
static class Duck implements Animal {
@Override public void say() { System.out.println("呱呱"); }
@Override public void say(String words) { System.out.println("卧槽:" + words); } }
static class ProxyOfAnimal implements InvocationHandler {
Animal animal;
public ProxyOfAnimal(Animal animal) { this.animal = animal; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Proxy invoke"); System.out.println(method); return method.invoke(this.animal, args); } }
public static void main(String[] args) { Duck duck = new Duck(); ProxyOfAnimal proxyOfAnimal = new ProxyOfAnimal(duck); Animal got = (Animal) Proxy.newProxyInstance(duck.getClass().getClassLoader(), duck.getClass().getInterfaces(), proxyOfAnimal); System.out.println(got.getClass().getName()); got.say(); got.say("wawa"); } }
|
控制台
1 2 3 4 5 6 7 8 9
| $Proxy0 Proxy invoke public abstract void DynamicProxyTest$Animal.say() 呱呱 Proxy invoke public abstract void DynamicProxyTest$Animal.say(java.lang.String) 卧槽:wawa
Process finished with exit code 0
|
InvocationHandler.invoke(Object proxy, Method method, Object[] args) 第一个参数是 Proxy.newProxyInstance 的返回对象,即 $Proxy0。可能是老接口没设计好,这个proxy在这里就是 this。
局限性:Proxy.newProxyInstance 只能返回接口Animal,不能返回对象Duck;不支持对static方法的代理。
优点:所谓的‘动态’只不过是调用某方法时去执行我事先定义好的handler方法,虽然我不必像静态代理那样写一个代理类,但是我需要写一个handler。但是我现在只需要写一个handler,就能产生Duck、Dog、Cat的代理类。
CGLIB动态代理
http://www.importnew.com/27772.html
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。
spring的@Transactional注解不能用在static方法上就很好理解了。spring使用cglib代理,而cglib通过继承方式实现代理,那么static方法不能继承(它不属于任何对象),就不能被代理了。同样,final修饰的方法(不能被override)、final 修饰的类(不能被继承)也不能被代理。
cglib给的一个演示示例,理解其如何实现动态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
| package net.sf.cglib.samples;
import java.beans.*;
public abstract class Bean implements java.io.Serializable{ String sampleProperty; abstract public void addPropertyChangeListener(PropertyChangeListener listener); abstract public void removePropertyChangeListener(PropertyChangeListener listener); public String getSampleProperty(){ return sampleProperty; } public void setSampleProperty(String value){ System.out.println("base bean"); this.sampleProperty = value; } public String toString(){ return "sampleProperty is " + sampleProperty; } }
package net.sf.cglib.samples;
import java.beans.*; import java.lang.reflect.*; import net.sf.cglib.proxy.*;
public class Beans implements MethodInterceptor { private PropertyChangeSupport propertySupport; public void addPropertyChangeListener(PropertyChangeListener listener) { propertySupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { propertySupport.removePropertyChangeListener(listener); }
public static Object newInstance( Class clazz ){ try{ Beans interceptor = new Beans(); Enhancer e = new Enhancer(); e.setSuperclass(clazz); e.setCallback(interceptor); Object bean = e.create(); interceptor.propertySupport = new PropertyChangeSupport( bean ); return bean; }catch( Throwable e ){ e.printStackTrace(); throw new Error(e.getMessage()); } } static final Class C[] = new Class[0]; static final Object emptyArgs [] = new Object[0];
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { Object retValFromSuper = null; try { if (!Modifier.isAbstract(method.getModifiers())) { retValFromSuper = proxy.invokeSuper(obj, args); } } finally { String name = method.getName(); if( name.equals("addPropertyChangeListener")) { addPropertyChangeListener((PropertyChangeListener)args[0]); }else if ( name.equals( "removePropertyChangeListener" ) ){ removePropertyChangeListener((PropertyChangeListener)args[0]); } if( name.startsWith("set") && args.length == 1 && method.getReturnType() == Void.TYPE ){ char propName[] = name.substring("set".length()).toCharArray(); propName[0] = Character.toLowerCase( propName[0] ); propertySupport.firePropertyChange( new String( propName ) , null , args[0]); } } return retValFromSuper; } public static void main( String args[] ){ Bean bean = (Bean)newInstance( Bean.class ); bean.addPropertyChangeListener( new PropertyChangeListener(){ public void propertyChange(PropertyChangeEvent evt){ System.out.println(evt); } } ); bean.setSampleProperty("TEST"); } }
|
控制台
1 2 3 4
| base bean java.beans.PropertyChangeEvent[propertyName=sampleProperty; oldValue=null; newValue=TEST; propagationId=null; source=sampleProperty is TEST]
Process finished with exit code 0
|
Spring 是如何添加事务的呢?大概是这个样子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class TxDemo { static class Dao { public void save(String obj) { System.out.println("save entity: " + obj); } }
static class Proxy implements MethodInterceptor {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { Object retObj = null; System.out.println("tx begin"); try { retObj = methodProxy.invokeSuper(o, objects); System.out.println("tx commit"); } catch (Exception e) { e.printStackTrace(); System.out.println("tx rollback"); } return retObj; } }
public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Dao.class); enhancer.setCallback(new Proxy()); Dao got = (Dao) enhancer.create(); got.save("user"); } }
|
控制台
1 2 3 4 5
| tx begin save entity: user tx commit
Process finished with exit code 0
|