代理,注解,接口和实现类的小测验

编程

* retention : 保留

* policy : 策略

ps : 简单测试了一下手写代理,jdk动态代理,和cglib动态代理,根据其不同的结果分析其原理

一:测试目的

  • 主要想看一下不同的代理模式对于目标类中方法上注解的读取能力

二:代理简述

  • jdk动态代理:只针对接口操作
  • cglib动态代理:既可以为没有实现接口的类去做代理,也可以为实现接口的类去做代理

三:代码准备

1)自定义注解

  • 设置保留策略为运行期
  • 注解中只定义一个数组
  • 当属性名为value时,注解中可以省略不写

@Retention(RetentionPolicy.RUNTIME)

public @interface MyAnno {

String[] value();

}

2)接口

public interface Service {

void eat();

}

3)实现类

  • 在eat()方法上添加自定义注解

public class ServiceImpl implements Service {

@Override

@MyAnno({"jim","tom"})

public void eat() {

System.out.println("eat ... ");

}

}

三:测试实例

1)手写代理模式

public class AnnoTest implements Service{

@MyAnno({ "jim", "tom" })

public void test() {

System.out.println("test...");

}

private Service target;

public AnnoTest(Service target) {

this.target = target;

}

@Override

public void eat() {

try {

Class clazz = target.getClass();

Method method = clazz.getMethod("eat");

if(method.isAnnotationPresent(MyAnno.class)) {

MyAnno myAnno = method.getAnnotation(MyAnno.class);

System.out.println(myAnno.value()[0]);

target.eat();

System.out.println(myAnno.value()[1]);

}else {

target.eat();

}

} catch (Exception e) {

e.printStackTrace();

}

}

public static void main(String[] args) throws Exception {

Service service = new ServiceImpl();

AnnoTest annoTest = new AnnoTest(service);

annoTest.eat();

}

}

  • 测试结果

jim

eat ...

tom

  • 原理分析 : 这个应该比较容易理解,就是一个父类引用指向子类对象,调用方法的时候调用的是实现类的方法实现,我们调用的时候,是在代理对象的eat()方法中判断目标类的eat()方法上有没有我们的注解,能读到很正常

2)JDK动态代理

public class AnnoTest2 implements InvocationHandler{

private Service target;

public AnnoTest2(Service target) {

this.target = target;

}

public Object createProxy() {

return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);

}

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

Object ret = null;

if(method.isAnnotationPresent(MyAnno.class)) {

MyAnno anno = method.getAnnotation(MyAnno.class);

System.out.println(anno.value()[0]);

ret = method.invoke(target, args);

System.out.println(anno.value()[1]);

}else {

ret = method.invoke(target, args);

}

return ret;

}

public static void main(String[] args) throws Exception {

Service service = new ServiceImpl();

AnnoTest2 annoTest = new AnnoTest2(service);

Service proxy = (Service) annoTest.createProxy();

proxy.eat();

}

}

  • 运行结果

eat ... 

  • 原理分析 : jdk动态代理,它代理的是接口,然后根据反射技术进行实现,通过invoke()方法我们可以知道,我们是在调用代理实例的方法,接口上并没有我们的自定义注解,所以代理实例上也不会有注解
  • 如果在接口上加上注解,则可以读到

3)CGLIB动态代理

public class AnnoTest3 implements MethodInterceptor {

private Object target;

public AnnoTest3(Object target) {

this.target = target;

}

public Object createProxy() {

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(target.getClass());

enhancer.setCallback(this);

return enhancer.create();

}

@Override

public Object intercept(Object object, Method method, Object[] args, MethodProxy arg3) throws Throwable {

Object ret = null;

if(method.isAnnotationPresent(MyAnno.class)) {

MyAnno anno = method.getAnnotation(MyAnno.class);

String[] val = anno.value();

System.out.println(val[0]);

ret = method.invoke(target, args);

System.out.println(val[1]);

}else {

ret = method.invoke(target, args);

}

return ret;

}

public static void main(String[] args) throws Exception {

Service service = new ServiceImpl();

AnnoTest3 annoTest = new AnnoTest3(service);

Service proxy = (Service) annoTest.createProxy();

proxy.eat();

}

}

  • 运行结果

jim

eat ...

tom

  • 原理分析 : cglib代理的目标对象是实现类对象,所以是可以读到的

以上是 代理,注解,接口和实现类的小测验 的全部内容, 来源链接: utcz.com/z/518137.html

回到顶部