* 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代理的目标对象是实现类对象,所以是可以读到的
来源:oschina
链接:https://my.oschina.net/u/4221889/blog/4340297