Java探索之——动态代理(JDK和CGlib方式)
2013-05-08 23:42
429 查看
动态代理是java中非常有用的特性之一,目前Spring作为MVC框架的主流选择,主要归功于其最重要的两个特性:Ioc和AOP,他们使得项目模块可以以一种非常松散的耦合的关系组织起来,大大减轻了开发者的负担。AOP正是动态代理实现的典型案例之一,动态代理目前主要有两种方式,JDK动态代理以及CGlib动态代理,下面以代码为例一一讲解。CGlib需要用到cglib和asm的jar包。
首先定义接口:
再定义实现类:
为了测试对注解的支持,定义一个注解MyAnnotation,@Retention注解表示注解的保存位置,@Target注解则表示该注解可以标记的目标。
JDK动态代理类,该类实现了InvocationHandler接口,需要在类中实现invoke方法。在本实例中invoke方法中获取了被代理方法中的@MyAnnotation注解的value值,并打印;若注解值为空串,则抛出异常。
实现CGlib动态代理类需要实现MethodInterceptor接口,该接口中有一个类似于invoke的方法intercept,从名字中可以看出,CGlib的AOP意味比JDK更浓,InvocationHandler更像一个纯代理接口。
测试类。在这里要特别注意,使用JDK动态代理时,由于其只支持接口,因此注解必须标记在接口上面才会生效,而且Proxy.newProxyInstance方法的第二个参数必须保证是一个接口class数组,否则将导致被代理类无法正常被加载并实例化。而在CGlib代理时,SayHelloImpl类不必实现任何接口。在这里也一并说说二者实现方式的区别,JDK方式是通过生成一个实现了代理接口的实现类来完成的代理,而CGLib则是通过继承被代理类,生成一个子类并覆盖子类的实现方法来完成的,因此,使用CGLib时,被代理对象不能被声明为final,否则无法实现继承。
运行结果:
首先定义接口:
public interface SayHello { @MyAnnotation("annotation declared in interface") public void sayHello(); }
再定义实现类:
public class SayHelloImpl implements SayHello{ @Override @MyAnnotation(value="annotation declared in method") public void sayHello() { System.out.println("Hello!"); } }
为了测试对注解的支持,定义一个注解MyAnnotation,@Retention注解表示注解的保存位置,@Target注解则表示该注解可以标记的目标。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyAnnotation { String value(); }
JDK动态代理类,该类实现了InvocationHandler接口,需要在类中实现invoke方法。在本实例中invoke方法中获取了被代理方法中的@MyAnnotation注解的value值,并打印;若注解值为空串,则抛出异常。
/** * 实现JDK动态代理接口类 * @author rui.chen * */ public class JDKProxy<T> implements InvocationHandler{ private T obj; public JDKProxy(T obj){ this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MyAnnotation ann = method.getAnnotation(MyAnnotation.class); if(ann!=null){ String value = ann.value(); if("".equals(value)){ System.out.println("You input a null value"); throw new NullPointerException(); }else{ System.out.println("Annotation:"+value); return method.invoke(obj, args); } }else{ return null; } } }
实现CGlib动态代理类需要实现MethodInterceptor接口,该接口中有一个类似于invoke的方法intercept,从名字中可以看出,CGlib的AOP意味比JDK更浓,InvocationHandler更像一个纯代理接口。
/** * 实现CGlib动态代理接口类 * @author rui.chen * */ public class CglibProxy<T> implements MethodInterceptor{ private T target; public Object getInstance(T target){ this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { MyAnnotation ann = method.getAnnotation(MyAnnotation.class); if(ann!=null){ String value = ann.value(); if("".equals(value)){ System.out.println("You input a null value"); throw new NullPointerException(); }else{ System.out.println("Annotation:"+value); return methodProxy.invoke(target, args); } }else{ return null; } } }
测试类。在这里要特别注意,使用JDK动态代理时,由于其只支持接口,因此注解必须标记在接口上面才会生效,而且Proxy.newProxyInstance方法的第二个参数必须保证是一个接口class数组,否则将导致被代理类无法正常被加载并实例化。而在CGlib代理时,SayHelloImpl类不必实现任何接口。在这里也一并说说二者实现方式的区别,JDK方式是通过生成一个实现了代理接口的实现类来完成的代理,而CGLib则是通过继承被代理类,生成一个子类并覆盖子类的实现方法来完成的,因此,使用CGLib时,被代理对象不能被声明为final,否则无法实现继承。
public class Run { /** * JDK动态代理测试 */ public static void JDKProxyTest(){ SayHello t = new SayHelloImpl(); InvocationHandler handler = new JDKProxy<SayHello>(t); SayHello p = (SayHello) Proxy.newProxyInstance(SayHello.class.getClassLoader(), new Class[]{SayHello.class},handler); /* * SayHello.class.getInterfaces()会导致无法实例化类,必须使用SayHelloImpl.class.getInterfaces() SayHello p = (SayHello) Proxy.newProxyInstance(SayHello.class.getClassLoader(), SayHello.class.getInterfaces(),handler); */ p.sayHello(); } /** * CGlib动态代理测试 */ public static void CGlibProxyTest(){ SayHelloImpl t = new SayHelloImpl(); CglibProxy<SayHelloImpl> cglib = new CglibProxy<SayHelloImpl>(); SayHelloImpl p = (SayHelloImpl) cglib.getInstance(t); p.sayHello(); } /** * @param args */ public static void main(String[] args) { JDKProxyTest(); CGlibProxyTest(); } }
运行结果:
Annotation:annotation declared in interface Hello! Annotation:annotation declared in method Hello!
相关文章推荐
- java动态代理的两种方式---jdk和cglib
- 三种实现动态代理方式(jdk、cglib、javaassist)
- 深入理解java动态代理的两种实现方式(JDK/Cglib)
- java 动态代理的两种方式(jdk,cglib)
- java动态代理(JDK和cglib)
- [z]Java代理(jdk静态代理、动态代理和cglib动态代理)
- Java动态代理之JDK实现和CGlib实现(简单易懂)火推笔记
- java jdk和cglib动态代理
- Java动态代理的之JDK和CGLIB
- Spring中AOP的两种代理方式(Java动态代理和CGLIB代理)
- Java之代理(jdk静态代理,jdk动态代理,cglib动态代理,aop,aspectj)
- java动态代理(JDK和cglib)
- java动态代理(JDK和cglib)
- Java代理(jdk静态代理、动态代理和cglib动态代理)实例及总结
- java动态代理(JDK和cglib)
- java动态代理(JDK和cglib)
- java动态代理(JDK和cglib)
- Java动态代理机制详解(JDK 和CGLIB)
- Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
- java动态代理(JDK和cglib)