JAVA JDK动态代理和CGLIB动态代理

时间:2022-02-13 20:16:30

  静态代理比较简单和装饰模式很相似,网上一堆资料,下面说说动态代理.
  
  JDK的动态代理是基于接口的,需要代理类和目标类都实现同一个接口,

  cglib的动态代理是基于类继承的,针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 ,所以被代理的类不能声明为final类型.

  并且使用JDK代理去动态读取某个目标类上面的自定义注解的属性你会发现读取不到,并且元注解使用的是RetentionPolicy.RUNTIME属性,但是不通过动态代理直接获取却能获取到,这是因为JDK的动态代理是基于接口的,所以用jdk动态代理通过method的 isAnnotationPresent(Annotation.class)方法读取目标类的方法注解就读取不到了,可以将目标类上面的注解放到接口上面去,然后使用JDK动态代理就能获取到了,当然如果使用CGLIB的动态代理就不存在这个问题了.

  下面用代码来简单测试下jdk和cglib的动态代理,在目标类的show方法上面加上自定义注解,并且使用动态代理在方法前后进行面向切面编程.

  项目结构如下:

JAVA JDK动态代理和CGLIB动态代理

  先写一个自定义注解MyAnnotation:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();
}

  代理接口类:

public interface MyService {

void show(String name);
}

  代理目标类:

public class MyServiceImpl implements MyService {
@MyAnnotation(value = "myAnnotation")
public void show(String name) {
System.out.println("show name is " + name);
}
}

  jdk的动态代理类:

public class JAVAAPIProxy implements InvocationHandler {

private Object target;

public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JAVAAPIProxy before");
method.invoke(target, args);
System.out.println("JAVAAPIProxy after");
boolean b = method.isAnnotationPresent(MyAnnotation.class);
System.out.println("JAVAAPIProxy " + b);
return null;
}
}

  cglib的动态代理类:

public class CGLIBProxy implements MethodInterceptor {

private Object target;

public Object bind(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CGLIBProxy before");
method.invoke(target, objects);
System.out.println("CGLIBProxy after");
boolean b = method.isAnnotationPresent(MyAnnotation.class);
System.out.println("CGLIBProxy "+b);
return null;
}
}

  测试主函数类:
  

public class MainClass {

public static void main(String[] args) {
testJAVAAPIProxy();
testCGLIBProxy();
}

public static void testJAVAAPIProxy() {
MyServiceImpl s = new MyServiceImpl();
JAVAAPIProxy proxy = new JAVAAPIProxy();
MyService bind = (MyService) proxy.bind(s);
bind.show("lijie");
}

public static void testCGLIBProxy() {
MyServiceImpl s = new MyServiceImpl();
CGLIBProxy proxy = new CGLIBProxy();
MyServiceImpl bind = (MyServiceImpl) proxy.bind(s);
bind.show("lijie");
}
}

  测试结果:

JAVA JDK动态代理和CGLIB动态代理