`
qindongliang1922
  • 浏览: 2183730 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
7265517b-f87e-3137-b62c-5c6e30e26109
证道Lucene4
浏览量:117527
097be4a0-491e-39c0-89ff-3456fadf8262
证道Hadoop
浏览量:125921
41c37529-f6d8-32e4-8563-3b42b2712a50
证道shell编程
浏览量:59896
43832365-bc15-3f5d-b3cd-c9161722a70c
ELK修真
浏览量:71300
社区版块
存档分类
最新评论

重温java代理模式

    博客分类:
  • JAVA
阅读更多
文章关键词:java代理,jdk动态代理,cglib代理,AOP,切面编程

今天,逛技术博客时,无意间发现了一篇有关动态代理模式的文章,感觉写的不错,自己正好也在巩固下基础知识,虽然实际工作中用代理的模式的不是特别多,那是因为你使用的框架,已经帮你封装好了,所以,你可能感觉不到,但是感觉不到不但表不存在,了解下它的原理和使用场景还是能提高下逼格的。于是散仙总结了下文,还有一个实战小例子,用来帮助理解。下面开始:

一:什么是代理?
代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式一般涉及到的角色有:
抽象角色:声明真实对象和代理对象的共同接口;
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

说白了,代理模式其实就相当于找房子时的中介,你无须找到真实的房东,就可以把租房子这件事给办了,而且因为中介,所以便有了一些额外增强的功能,所以少数中介会提高房价或黑你一下,当然咱们的程序肯定不是跟中介一个德行的。


二:java中代理的种类
(1)静态代理: 只能提供固定的类的代理,局限性比较大
(2)JDK动态代理:只能代理接口,通过反射,提高了灵活性,但性能稍慢
(3)CGLIB代理:Spring AOP的默认实现,可以代理类,无须提供对应接口,通过ASM(asm是Java字节码操控框架,ASM是一套java字节码生成架构,它可以动态生成二进制格式的stub类或其它代理类,或者在类被java虚拟机装入内存之前,动态修改类)字节码增强,速度要快于JDK的默认的动态代理。


三:使用代理的应用场景

这个问题,其实就跟问Spring AOP切面编程的好处,就非常类似了,通过代理模式,我们可以无侵入式的,很方便的实现日志记录功能,方法权限拦截功能,事务控制等功能。


四:实战例子
项目结构:




百度云盘下载: http://pan.baidu.com/s/1eQ0h5YE
1,JDK动态代理,模拟事务控制功能,已经记录方法的耗时功能 

package com.easy.model;
/***
 * 
 * @author qindongliang
 *
 */
public class Person {
	
	//用户名
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	
	
	public Person(String name) {
		super();
		this.name = name;
	}

	public Person() {
		// TODO Auto-generated constructor stub
	}

}

Dao接口已经实现类,里面含有测试的方法:
package com.easy.dao;

import com.easy.model.Person;
/***
 * 动态代理测试dao
 * @author qindongliang
 *
 */
public interface PersonDao {
	//add user
	public void addUser(Person user);
	//delete user
	public void deleteUser(String name);
	//update user
	public void updateUser(String name);

}

实现类:
package com.easy.dao.impl;

import com.easy.dao.PersonDao;
import com.easy.model.Person;
/***
 * Dao的实现类
 * @author qindongliang
 *
 */
public class PersonDaoImpl implements PersonDao {

	@Override
	public void addUser(Person user) {
		// TODO Auto-generated method stub
//		System.out.println("add user name: "+user.getName());
		try{
			Thread.sleep(1000);//sleep 1 second
		}catch(Exception e){
			e.printStackTrace();
		}
	}

	@Override
	public void deleteUser(String name) {
//		System.out.println("delete user name: "+name);
		try{
			Thread.sleep(1500);//sleep 1.5 second
		}catch(Exception e){
			e.printStackTrace();
		}
		
	}

	@Override
	public void updateUser(String name) {
//		System.out.println("update user name: "+name);
		try{
			Thread.sleep(2000);//sleep 2 second
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	

}

JDK动态代理实现:
package com.easy.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
/***
 * JDK动态代理例子
 * @author qindongliang
 *
 */
public class JDK_Proxy implements InvocationHandler {
	
	//代理实例
	private Object proxy;
	//通过构造参数赋值
	public JDK_Proxy(Object proxy) {
		this.proxy = proxy;
	}

	//格式化时间
	private static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
	
	



	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object obj=null;
		//开始时间
		long start=System.currentTimeMillis();
		//以add开头的方法,加入事务控制
		if(method.getName().startsWith("add")){
			//开启事务
			startTransaction(method);
			obj=method.invoke(this.proxy, args);
			//关闭事务
			closeTransaction(method);
		}else{
			obj=method.invoke(this.proxy, args);
		}
		
		//调用结束时间
		long end=System.currentTimeMillis();
		System.out.println(sdf.format(new Date())+"  "+method.getName()+"调用方法执行时间为:"+(end-start)/1000+"秒!");
		System.out.println();
		return obj;
	}
	
	//模拟开启事务
	public void startTransaction(Method method){
		System.out.println("请注意:"+method.getName()+"开启了 commit 事务操作 !");
	}
	
	//模拟关闭事务
	public void closeTransaction(Method method){
		System.out.println("请注意:"+method.getName()+"关闭了 commit 事务操作 !");
	}
	
	
	
	
	
	
	
	

}

无接口的cglib代理测试类:
package com.easy.dao.impl;

/***
 * 此类没有实现任何接口,只能使用Cglib代理来调用方法
 * 必须有无参的构造方法
 * @author qindongliang
 *
 */
public class CarManager {
	
	private String name;
	
	
	public CarManager() {
		// TODO Auto-generated constructor stub
	}
	
	public CarManager(String name) {
		this.name = name;
	}



	public String getName() {
		return name;
	}



	public void setName(String name) {
		this.name = name;
	}



	public void run()throws Exception{
		System.out.println(this.getName()+"汽车启动了!");
		Thread.sleep(3000);
	}

	
	
	public void stop(){
		System.out.println(this.getName()+"汽车停止了!");
	}
	
	
	

}

  Cglib代理的实现:
package com.easy.proxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/***
 * Cglib代理测试
 * @author qindongliang
 */
public class CGLIB_Proxy implements MethodInterceptor{

	//代理对象
	private Object target;
	
	
	
	 @SuppressWarnings("unchecked")  
	 public static <T> T proxyTarget(T t) {  
	        Enhancer en = new Enhancer();  
	        en.setSuperclass(t.getClass());  
	        en.setCallback(new CGLIB_Proxy(t));  
	        T tt = (T) en.create();  
	        return tt;  
	 }  
	
	 
	public CGLIB_Proxy(Object target) {
		this.target = target;
	}





	@Override
	public Object intercept(Object arg0, Method method, Object[] args,MethodProxy arg3) throws Throwable {
		
		System.out.println("调用 "+method.getName()+" 开始......  ");
		//调用代理
		Object obj=method.invoke(this.target, args);
		System.out.println("调用 "+method.getName()+" 结束......  ");
		return obj;
	}
	
	
	
	
	
	

}

测试的代码:
package com.easy.main;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

import com.easy.dao.PersonDao;
import com.easy.dao.impl.CarManager;
import com.easy.dao.impl.PersonDaoImpl;
import com.easy.model.Person;
import com.easy.proxy.CGLIB_Proxy;
import com.easy.proxy.JDK_Proxy;

/**
 * 包含jdk动态代理和cglib代理的测试
 * @author qindongliang
 *
 */
public class MethodTest {
	
	public static void main(String[] args) throws Exception {
		//cglibProxyTest();
		jdkProxyTest();
	}

	
	/****
	 * cglib代理测试
	 */
	public static void cglibProxyTest()throws Exception{
		
		
		CarManager car=new CarManager("大众");
//		
//		car.run();
//		car.stop();
		//得到代理类对象
		CarManager carManager=CGLIB_Proxy.proxyTarget(car);
		carManager.run();
		
		
		
		
		
	}
	
	
	/***
	 * jdk动态代理
	 */
	public static void jdkProxyTest() {
		PersonDao user=new PersonDaoImpl();
		
		Class<?> cls=user.getClass();
		
		InvocationHandler handler=new JDK_Proxy(user);
		
		//转换得来的代理对象
		PersonDao proxy=(PersonDao)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), handler);
		
		proxy.addUser(new Person("hadoop"));
		proxy.deleteUser("lucene");
		proxy.updateUser("solr and elasticsearch");
	}
	
	
 
	
	

}



测试JDK动态代理结果:





测试cglib代理结果:



总结:使用代理模式,在一些场景,非常灵活,而且无侵入式的发挥巨大的作用,这就是面向切面编程的核心思想。



最后欢迎大家扫码关注微信公众号:我是攻城师(woshigcs),我们一起学习,进步和交流!(woshigcs)
本公众号的内容是有关搜索和大数据技术和互联网等方面内容的分享,也是一个温馨的技术互动交流的小家园,有什么问题随时都可以留言,欢迎大家来访!


参考文章:

http://andy136566.iteye.com/blog/967952
http://www.cnblogs.com/coderworld/p/java-reflect.html
http://blog.csdn.net/leon709/article/details/9529307
http://www.cnblogs.com/coderworld/p/java-dynamic-proxy.htm






  • 大小: 17.3 KB
  • 大小: 103.7 KB
  • 大小: 19.4 KB
5
3
分享到:
评论
2 楼 qindongliang1922 2015-10-09  
莫欺少年穷Java 写道

1 楼 莫欺少年穷Java 2015-10-09  

相关推荐

    java,android常用设计模式,单例,mvp

    本人深圳安卓开发程序猿一枚,希望能一起...最近重温了一下java的设计模式,练练手,java设计模式有23种,写了12种常用的设计模式,一些觉得用不上就没写,水平有限,有问题欢迎留言一起加油email:674928145@qq.com!

    重温 Thinking in Java 5 - The Class object

    例如,我们可以利用类对象进行泛型擦除后的类型检查,或者在设计模式如工厂方法、单例模式中发挥作用。此外,它在动态代理、注解处理等领域也发挥着关键作用。 总的来说,《Thinking in Java 5 - The Class object...

    java7源码-ReviewJavaFoundation:重温Java基础系列源代码

    所以,近段时间开始,将重温Java技术的基础知识,主版本为Java8,中间可能也会穿插一些其它版本,如Java7。谨以此系列文章,来记录重温Java基础的历程。 为啥费劲写这些文章?和写SpringCloud进阶之路时一样,一是...

    重温Observer模式--热水器·改

    在这个“重温Observer模式--热水器·改”的讨论中,作者将再次阐述如何不依赖C#的委托和事件来实现Observer模式,而是采用GOF(GoF,Gang of Four)的经典方式。 在Observer模式中,有两个核心角色:Subject(主题...

    43个java 经典手机游戏(打包下载)

    对于玩家而言,它们是一段美好的回忆,能够重温那些简单而纯粹的乐趣。 在这个压缩包中,你可以找到43款经过破解的Java游戏,它们代表了一个时代的结束,也是许多人的共同回忆。无论是为了怀旧还是学习,下载并体验...

    合金弹头之Java简易版

    《合金弹头之Java简易版》是一款基于Java编程语言实现的简单游戏,它以其经典的动作射击元素和像素艺术风格,为玩家提供了重温经典游戏的乐趣。在这个项目中,开发者利用Java的强大功能,创建了一个轻量级的游戏环境...

    重温微积分 - 齐民友

    重温微积分 - 齐民友

    电脑能用的java模拟器

    这在开发、调试或重温旧的Java游戏和应用时非常有用。 描述中的重复词语"java模拟器"强调了主题的核心,即我们讨论的是一个能够运行Java代码的模拟环境。虽然描述内容简单,但其重点在于强调模拟器的Java兼容性以及...

    全屏2.3_java模拟器

    这种模拟器允许用户在全屏模式下体验原本只适用于Java手机的游戏或应用,即使他们的设备不直接支持Java。 描述部分提到,由于许多用户使用的是安卓系统,而Android本身并不原生支持Java ME(Mobile Edition),这...

    Java游戏模拟 器

    Java游戏模拟器是一种基于Java编程语言开发的软件,它能够模拟不同的游戏平台,使得用户可以在计算机上运行原本设计为在移动设备(如早期的Java ME手机)或特定游戏设备上运行的Java游戏。这种模拟器通常利用Java...

    JavaApplet潜艇大战

    JavaApplet潜艇大战是一款基于Java Applet技术开发的小...通过分析和学习"JavaApplet潜艇大战",开发者不仅可以重温经典,还能从中汲取灵感,应用到现代框架和库,如JavaFX或Unity,创造出更加丰富和先进的游戏体验。

    Java环境jdk_1.6安装包

    1. **动态代理类**:Java 1.6添加了对动态代理类的支持,使得在运行时创建接口的代理类成为可能,这在实现AOP(面向切面编程)和事件处理等场景中非常有用。 2. **改进的Swing组件**:这一版本加强了Swing UI库,...

    Java EE 7 with GlassFish 4 Application Server 2014年英文原版

    除了重温Java服务器面(JSF),它解释了为什么Facelets的,在JSF的现代版本引入的新功能,是首选的视图技术对Java服务器页面(JSP) 在后面的章节中探讨的竞争在Java WebSocket的标准实现,描述了JMS的更新;其目的...

    手机JAVA版合金弹头

    总的来说,《手机JAVA版合金弹头》是JAVA平台上的一款经典射击游戏,它利用JAVA ME技术将街机游戏的魅力带到了移动设备上,让玩家随时随地都能重温那份射击冒险的刺激。虽然如今的智能手机已经发展到非常高级的阶段...

    手机JAVA模拟器超精简版(520k)

    总的来说,“手机JAVA模拟器超精简版(520k)”是一个便于用户在电脑上重温经典Java手机游戏的实用工具。它的存在,既是对过去技术的致敬,也为那些珍藏记忆的老玩家们提供了一条便捷的通道。虽然在现代高性能的移动...

    java版的坦克大战小游戏源码

    "Java版的坦克大战小游戏源码"就是一个极佳的实践项目,它不仅让我们有机会重温Java的基础知识,还能够深入理解多线程、内部类、图形绘制以及泛型等高级特性。下面,我们将详细探讨这个项目中的关键知识点。 首先,...

    最新版的PC端java模拟器KEmulator

    Java游戏在过去曾风靡一时,而现在,通过KEmulator,用户可以重温那些经典,不受设备限制。 首先,我们要理解Java模拟器的工作原理。Java模拟器实质上是在PC上创建一个虚拟环境,这个环境模拟了Java应用程序所需的...

    java手机游戏模拟器

    这种模拟器通常用于测试游戏、开发过程中的调试或者为那些不再拥有支持Java游戏的老式手机的用户重温经典游戏。 Java作为一门跨平台的编程语言,其在移动设备上的应用尤其广泛,特别是在早期的智能手机时代。Java ...

    java俄罗斯方块,经典小游戏

    《Java实现俄罗斯方块:重温经典编程挑战》 在编程世界中,俄罗斯方块是一款深受开发者喜爱的经典小游戏,它简洁的规则和丰富的策略性使其成为学习新语言或技术的绝佳练习项目。本项目以Java为编程语言,展示了如何...

Global site tag (gtag.js) - Google Analytics