代理代码实现
jdk动态代理
1、有个Person接口
package com.xiangwen.day5.jdk; public interface Person { public void say(String str); public void listen(String str); }
2、有个PersonImpl接口实现类
package com.xiangwen.day5.jdk; public class PersonImpl implements Person { @Override public void say(String str) { System.out.println(str); } @Override public void listen(String str) { System.out.println(str); } }
3、创建接口的代理类PersonProxy
package com.xiangwen.day5.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class PersonProx implements InvocationHandler { private Person person; public PersonProx(Person person) { this.person = person; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object o=null; if("say".equals(method.getName())){ System.out.println("111111111befre---------------"); o=method.invoke(person,args); System.out.println("111111111end-----------------"); }else if("listen".equals(method.getName())){ System.out.println("222222222befre---------------"); o=method.invoke(person,args); System.out.println("222222222end-----------------"); } return o; } }
4测试
package com.xiangwen.day5.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { Person person=new PersonImpl(); InvocationHandler personProx=new PersonProx(person); Person p= (Person) Proxy.newProxyInstance(personProx.getClass().getClassLoader(),person.getClass().getInterfaces(),personProx); p.say("hello"); System.out.println(); p.listen("祝你平安!"); } }
结果截图:
cglib动态代理
maven依赖:
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.11</version> </dependency> <dependency> <groupId>org.objectweb.asm</groupId> <artifactId>com.springsource.org.objectweb.asm</artifactId> <version>3.1.0</version> </dependency>
1.有一个类PerosonImpl
package com.xiangwen.day5.cglib; import com.xiangwen.day5.jdk.Person; public class PersonImpl { public void say(String str) { System.out.println("说:"+str); } public void listen(String str) { System.out.println("听:"+str); } }
2、建一个代理类为方法1处理
package com.xiangwen.day5.cglib; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class PersonProx implements MethodInterceptor { @Override public Object intercept(Object object, Method method, Object[] objects, MethodProxy proxy) throws Throwable { System.out.println("Before Method Invoke"); proxy.invokeSuper(object, objects); System.out.println("After Method Invoke"); return object; } }
3、建第二个代理类为方法2处理
package com.xiangwen.day5.cglib; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class PersonProx2 implements MethodInterceptor { @Override public Object intercept(Object object, Method method, Object[] objects, MethodProxy proxy) throws Throwable { System.out.println("PersonProx2====Before Method Invoke"); proxy.invokeSuper(object, objects); System.out.println("PersonProx2====After Method Invoke"); return object; } }
4、建一个MyFilter方法与代理类的顺序
package com.xiangwen.day5.cglib;
import net.sf.cglib.proxy.CallbackFilter;
import java.lang.reflect.Method;
public class MyFilter implements CallbackFilter {
@Override
public int accept(Method method) {
if("say".equals(method.getName())){
return 0;
}else if("listen".equals(method.getName())){
return 1;
}
return 1;//下标不能超过new Callback[]数组的下表,否则会报错
}
}
5、测试
@org.junit.Test public void test2(){ PersonProx personProxy = new PersonProx(); PersonProx2 personProxy2 = new PersonProx2(); MyFilter filter=new MyFilter(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(PersonImpl.class); enhancer.setCallbacks(new Callback[]{personProxy,personProxy2}); enhancer.setCallbackFilter(filter); PersonImpl person = (PersonImpl)enhancer.create(); person.say("说你爱我"); System.out.println(); person.listen("听雨"); }
6、结果截图
如果不单独指定代理,所有方法都用personProxy代理
public static void main(String[] args) { PersonProx personProxy = new PersonProx(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(PersonImpl.class); enhancer.setCallback(personProxy); PersonImpl person = (PersonImpl)enhancer.create(); person.say("说你爱我"); person.listen("听雨"); }
区别:
jdk:利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,
在调用具体方法前调用InvokeHandler来处理。
JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
cglib:利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,
并覆盖其中方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成final,
对于final类或方法,是无法继承的。
什么情况使用:
1)如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。
2)如果目标对象实现了接口,可以强制使用CGLIB实现AOP。
3)如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换。
1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在jdk6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
2)在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理,总之,每一次jdk版本升级,jdk代理效率都得到提升,而CGLIB代理效率确有点跟不上步伐。