文档章节

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

岁一
 岁一
发布于 07/08 14:55
字数 815
阅读 73
收藏 0

「深度学习福利」大神带你进阶工程师,立即查看>>>

* 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代理的目标对象是实现类对象,所以是可以读到的
岁一
粉丝 30
博文 21
码字总数 29373
作品 0
朝阳
私信 提问
加载中
请先登录后再评论。
Netty那点事(三)Channel与Pipeline

Channel是理解和使用Netty的核心。Channel的涉及内容较多,这里我使用由浅入深的介绍方法。在这篇文章中,我们主要介绍Channel部分中Pipeline实现机制。为了避免枯燥,借用一下《盗梦空间》的...

黄亿华
2013/11/24
2W
22
访问安全控制解决方案

本文是《轻量级 Java Web 框架架构设计》的系列博文。 今天想和大家简单的分享一下,在 Smart 中是如何做到访问安全控制的。也就是说,当没有登录或 Session 过期时所做的操作,会自动退回到...

黄勇
2013/11/03
3.7K
8
用vertx实现高吞吐量的站点计数器

工具:vertx,redis,mongodb,log4j 源代码地址:https://github.com/jianglibo/visitrank 先看架构图: 如果你不熟悉vertx,请先google一下。我这里将vertx当作一个容器,上面所有的圆圈要...

jianglibo
2014/04/03
4.4K
3
浅入浅出Android(003):使用TextView类构造文本控件

基础: TextView是无法供编辑的。 当我们新建一个项目MyTextView时候,默认的布局(/res/layout/activity_main.xml)中已经有了一个TextView: <TextView 运行效果如下: 修改其文本内容...

樂天
2014/03/22
720
1
SQLServer实现split分割字符串到列

网上已有人实现sqlserver的split函数可将字符串分割成行,但是我们习惯了split返回数组或者列表,因此这里对其做一些改动,最终实现也许不尽如意,但是也能解决一些问题。 先贴上某大牛写的s...

cwalet
2014/05/21
9.7K
0

没有更多内容

加载失败,请刷新页面

加载更多

【实用技巧】MAC苹果电脑怎么远程?

一般电脑远程包括三方面: 1、如果从外部windows或者linux终端连接到mac苹果电脑; 2、从苹果电脑内如何远程外面的windows、linux和mac等; 3、苹果和安卓手机怎么远程连接苹果/Windows电脑。...

osc_doeya1ck
55分钟前
22
0
虚拟主机和VPS主机有哪些不同点呢

虚拟主机是一种在单一主机或主机群上,实现多网域服务的方法,可以运行多个网站或服务的技术。vps主机是将一台服务器分割成多个虚拟专享服务器的服务。实现VPS的技术分为容器技术和虚拟机技术...

osc_b88oux8w
57分钟前
19
0
合理的使用MySQL乐观锁与悲观锁

针对 MySQL的乐观锁与悲观锁的使用,基本都是按照业务场景针对性使用的。针对每个业务场景,对应的使用锁。 但是两种锁无非都是解决并发所产生的问题。下面我们来看看如何合理的使用乐观锁与...

php开源社区
57分钟前
13
0
fusionpbx 中文 汉化

  自己以前有从事过呼叫中心的工作经验,然而由于自己是从事后端开发,对于前端界面的开发还是有些吃力,但是自己却又想自己搭建一套呼叫中心,所以购买了一台云服务器并克隆了FusionPBX的...

osc_ydeb2o99
59分钟前
12
0
关于大O表示法和小O表示法

上节课老师讲了一下各种表示法,当时没咋听懂,后来查了一些资料弄懂了,记录一下。 主要是从维基百科上看的。http://en.wikipedia.org/wiki/Big_O_notation 大O表示法: f(x) = O(g(x)) 表示...

osc_3mzamgkq
今天
18
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部