专栏首页我是攻城师重温java代理模式

重温java代理模式

文章关键词:java代理,jdk动态代理,cglib代理,AOP,切面编程 (由于有代码,文章格式稍乱,请多原谅包涵,代码部分,小伙伴们可以直接点击去iteye博客上看:http://qindongliang.iteye.com/blog/2247670 文中也有百度网盘源码地址可供下载!)

今天,逛技术博客时,无意间发现了一篇有关动态代理模式的文章,感觉写的不错,自己正好也在巩固下基础知识,虽然实际工作中用代理的模式的不是特别多,那是因为你使用的框架,已经帮你封装好了,所以,你可能感觉不到,但是感觉不到不但表不存在,了解下它的原理和使用场景还是能提高下逼格的。于是散仙总结了下文,还有一个实战小例子,用来帮助理解。下面开始: 一:什么是代理? 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 代理模式一般涉及到的角色有: 抽象角色:声明真实对象和代理对象的共同接口; 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。 说白了,代理模式其实就相当于找房子时的中介,你无须找到真实的房东,就可以把租房子这件事给办了,而且因为中介,所以便有了一些额外增强的功能,所以少数中介会提高房价或黑你一下,当然咱们的程序肯定不是跟中介一个德行的。 二: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动态代理,模拟事务控制功能,已经记录方法的耗时功能

Java代码

  1. package com.easy.model;
  2. /***
  3. *
  4. * @author qindongliang
  5. *
  6. */
  7. public class Person {
  8. //用户名
  9. private String name;
  10. public String getName() {
  11. return name;
  12. }
  13. public void setName(String name) {
  14. this.name = name;
  15. }
  16. public Person(String name) {
  17. super();
  18. this.name = name;
  19. }
  20. public Person() {
  21. // TODO Auto-generated constructor stub
  22. }
  23. }

[java] view plaincopy

  1. package com.easy.model;
  2. /***
  3. *
  4. * @author qindongliang
  5. *
  6. */
  7. public class Person {
  8. //用户名
  9. private String name;
  10. public String getName() {
  11. return name;
  12. }
  13. public void setName(String name) {
  14. this.name = name;
  15. }
  16. public Person(String name) {
  17. super();
  18. this.name = name;
  19. }
  20. public Person() {
  21. // TODO Auto-generated constructor stub
  22. }
  23. }

Dao接口已经实现类,里面含有测试的方法:

Java代码

  1. package com.easy.dao;
  2. import com.easy.model.Person;
  3. /***
  4. * 动态代理测试dao
  5. * @author qindongliang
  6. *
  7. */
  8. public interface PersonDao {
  9. //add user
  10. public void addUser(Person user);
  11. //delete user
  12. public void deleteUser(String name);
  13. //update user
  14. public void updateUser(String name);
  15. }

[java] view plaincopy

  1. package com.easy.dao;
  2. import com.easy.model.Person;
  3. /***
  4. * 动态代理测试dao
  5. * @author qindongliang
  6. *
  7. */
  8. public interface PersonDao {
  9. //add user
  10. public void addUser(Person user);
  11. //delete user
  12. public void deleteUser(String name);
  13. //update user
  14. public void updateUser(String name);
  15. }

实现类:

Java代码

  1. package com.easy.dao.impl;
  2. import com.easy.dao.PersonDao;
  3. import com.easy.model.Person;
  4. /***
  5. * Dao的实现类
  6. * @author qindongliang
  7. *
  8. */
  9. public class PersonDaoImpl implements PersonDao {
  10. @Override
  11. public void addUser(Person user) {
  12. // TODO Auto-generated method stub
  13. // System.out.println("add user name: "+user.getName());
  14. try{
  15. Thread.sleep(1000);//sleep 1 second
  16. }catch(Exception e){
  17. e.printStackTrace();
  18. }
  19. }
  20. @Override
  21. public void deleteUser(String name) {
  22. // System.out.println("delete user name: "+name);
  23. try{
  24. Thread.sleep(1500);//sleep 1.5 second
  25. }catch(Exception e){
  26. e.printStackTrace();
  27. }
  28. }
  29. @Override
  30. public void updateUser(String name) {
  31. // System.out.println("update user name: "+name);
  32. try{
  33. Thread.sleep(2000);//sleep 2 second
  34. }catch(Exception e){
  35. e.printStackTrace();
  36. }
  37. }
  38. }

[java] view plaincopy

  1. package com.easy.dao.impl;
  2. import com.easy.dao.PersonDao;
  3. import com.easy.model.Person;
  4. /***
  5. * Dao的实现类
  6. * @author qindongliang
  7. *
  8. */
  9. public class PersonDaoImpl implements PersonDao {
  10. @Override
  11. public void addUser(Person user) {
  12. // TODO Auto-generated method stub
  13. // System.out.println("add user name: "+user.getName());
  14. try{
  15. Thread.sleep(1000);//sleep 1 second
  16. }catch(Exception e){
  17. e.printStackTrace();
  18. }
  19. }
  20. @Override
  21. public void deleteUser(String name) {
  22. // System.out.println("delete user name: "+name);
  23. try{
  24. Thread.sleep(1500);//sleep 1.5 second
  25. }catch(Exception e){
  26. e.printStackTrace();
  27. }
  28. }
  29. @Override
  30. public void updateUser(String name) {
  31. // System.out.println("update user name: "+name);
  32. try{
  33. Thread.sleep(2000);//sleep 2 second
  34. }catch(Exception e){
  35. e.printStackTrace();
  36. }
  37. }
  38. }

JDK动态代理实现:

Java代码

  1. package com.easy.proxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.text.SimpleDateFormat;
  5. import java.util.Date;
  6. /***
  7. * JDK动态代理例子
  8. * @author qindongliang
  9. *
  10. */
  11. public class JDK_Proxy implements InvocationHandler {
  12. //代理实例
  13. private Object proxy;
  14. //通过构造参数赋值
  15. public JDK_Proxy(Object proxy) {
  16. this.proxy = proxy;
  17. }
  18. //格式化时间
  19. private static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
  20. @Override
  21. public Object invoke(Object proxy, Method method, Object[] args)
  22. throws Throwable {
  23. Object obj=null;
  24. //开始时间
  25. long start=System.currentTimeMillis();
  26. //以add开头的方法,加入事务控制
  27. if(method.getName().startsWith("add")){
  28. //开启事务
  29. startTransaction(method);
  30. obj=method.invoke(this.proxy, args);
  31. //关闭事务
  32. closeTransaction(method);
  33. }else{
  34. obj=method.invoke(this.proxy, args);
  35. }
  36. //调用结束时间
  37. long end=System.currentTimeMillis();
  38. System.out.println(sdf.format(new Date())+" "+method.getName()+"调用方法执行时间为:"+(end-start)/1000+"秒!");
  39. System.out.println();
  40. return obj;
  41. }
  42. //模拟开启事务
  43. public void startTransaction(Method method){
  44. System.out.println("请注意:"+method.getName()+"开启了 commit 事务操作 !");
  45. }
  46. //模拟关闭事务
  47. public void closeTransaction(Method method){
  48. System.out.println("请注意:"+method.getName()+"关闭了 commit 事务操作 !");
  49. }
  50. }

[java] view plaincopy

  1. package com.easy.proxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.text.SimpleDateFormat;
  5. import java.util.Date;
  6. /***
  7. * JDK动态代理例子
  8. * @author qindongliang
  9. *
  10. */
  11. public class JDK_Proxy implements InvocationHandler {
  12. //代理实例
  13. private Object proxy;
  14. //通过构造参数赋值
  15. public JDK_Proxy(Object proxy) {
  16. this.proxy = proxy;
  17. }
  18. //格式化时间
  19. private static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
  20. @Override
  21. public Object invoke(Object proxy, Method method, Object[] args)
  22. throws Throwable {
  23. Object obj=null;
  24. //开始时间
  25. long start=System.currentTimeMillis();
  26. //以add开头的方法,加入事务控制
  27. if(method.getName().startsWith("add")){
  28. //开启事务
  29. startTransaction(method);
  30. obj=method.invoke(this.proxy, args);
  31. //关闭事务
  32. closeTransaction(method);
  33. }else{
  34. obj=method.invoke(this.proxy, args);
  35. }
  36. //调用结束时间
  37. long end=System.currentTimeMillis();
  38. System.out.println(sdf.format(new Date())+" "+method.getName()+"调用方法执行时间为:"+(end-start)/1000+"秒!");
  39. System.out.println();
  40. return obj;
  41. }
  42. //模拟开启事务
  43. public void startTransaction(Method method){
  44. System.out.println("请注意:"+method.getName()+"开启了 commit 事务操作 !");
  45. }
  46. //模拟关闭事务
  47. public void closeTransaction(Method method){
  48. System.out.println("请注意:"+method.getName()+"关闭了 commit 事务操作 !");
  49. }
  50. }

无接口的cglib代理测试类:

Java代码

  1. package com.easy.dao.impl;
  2. /***
  3. * 此类没有实现任何接口,只能使用Cglib代理来调用方法
  4. * 必须有无参的构造方法
  5. * @author qindongliang
  6. *
  7. */
  8. public class CarManager {
  9. private String name;
  10. public CarManager() {
  11. // TODO Auto-generated constructor stub
  12. }
  13. public CarManager(String name) {
  14. this.name = name;
  15. }
  16. public String getName() {
  17. return name;
  18. }
  19. public void setName(String name) {
  20. this.name = name;
  21. }
  22. public void run()throws Exception{
  23. System.out.println(this.getName()+"汽车启动了!");
  24. Thread.sleep(3000);
  25. }
  26. public void stop(){
  27. System.out.println(this.getName()+"汽车停止了!");
  28. }
  29. }

[java] view plaincopy

  1. package com.easy.dao.impl;
  2. /***
  3. * 此类没有实现任何接口,只能使用Cglib代理来调用方法
  4. * 必须有无参的构造方法
  5. * @author qindongliang
  6. *
  7. */
  8. public class CarManager {
  9. private String name;
  10. public CarManager() {
  11. // TODO Auto-generated constructor stub
  12. }
  13. public CarManager(String name) {
  14. this.name = name;
  15. }
  16. public String getName() {
  17. return name;
  18. }
  19. public void setName(String name) {
  20. this.name = name;
  21. }
  22. public void run()throws Exception{
  23. System.out.println(this.getName()+"汽车启动了!");
  24. Thread.sleep(3000);
  25. }
  26. public void stop(){
  27. System.out.println(this.getName()+"汽车停止了!");
  28. }
  29. }

Cglib代理的实现:

Java代码

  1. package com.easy.proxy;
  2. import java.lang.reflect.Method;
  3. import net.sf.cglib.proxy.Enhancer;
  4. import net.sf.cglib.proxy.MethodInterceptor;
  5. import net.sf.cglib.proxy.MethodProxy;
  6. /***
  7. * Cglib代理测试
  8. * @author qindongliang
  9. */
  10. public class CGLIB_Proxy implements MethodInterceptor{
  11. //代理对象
  12. private Object target;
  13. @SuppressWarnings("unchecked")
  14. public static <T> T proxyTarget(T t) {
  15. Enhancer en = new Enhancer();
  16. en.setSuperclass(t.getClass());
  17. en.setCallback(new CGLIB_Proxy(t));
  18. T tt = (T) en.create();
  19. return tt;
  20. }
  21. public CGLIB_Proxy(Object target) {
  22. this.target = target;
  23. }
  24. @Override
  25. public Object intercept(Object arg0, Method method, Object[] args,MethodProxy arg3) throws Throwable {
  26. System.out.println("调用 "+method.getName()+" 开始...... ");
  27. //调用代理
  28. Object obj=method.invoke(this.target, args);
  29. System.out.println("调用 "+method.getName()+" 结束...... ");
  30. return obj;
  31. }
  32. }

[java] view plaincopy

  1. package com.easy.proxy;
  2. import java.lang.reflect.Method;
  3. import net.sf.cglib.proxy.Enhancer;
  4. import net.sf.cglib.proxy.MethodInterceptor;
  5. import net.sf.cglib.proxy.MethodProxy;
  6. /***
  7. * Cglib代理测试
  8. * @author qindongliang
  9. */
  10. public class CGLIB_Proxy implements MethodInterceptor{
  11. //代理对象
  12. private Object target;
  13. @SuppressWarnings("unchecked")
  14. public static <T> T proxyTarget(T t) {
  15. Enhancer en = new Enhancer();
  16. en.setSuperclass(t.getClass());
  17. en.setCallback(new CGLIB_Proxy(t));
  18. T tt = (T) en.create();
  19. return tt;
  20. }
  21. public CGLIB_Proxy(Object target) {
  22. this.target = target;
  23. }
  24. @Override
  25. public Object intercept(Object arg0, Method method, Object[] args,MethodProxy arg3) throws Throwable {
  26. System.out.println("调用 "+method.getName()+" 开始...... ");
  27. //调用代理
  28. Object obj=method.invoke(this.target, args);
  29. System.out.println("调用 "+method.getName()+" 结束...... ");
  30. return obj;
  31. }
  32. }

测试的代码:

Java代码

  1. package com.easy.main;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Proxy;
  4. import com.easy.dao.PersonDao;
  5. import com.easy.dao.impl.CarManager;
  6. import com.easy.dao.impl.PersonDaoImpl;
  7. import com.easy.model.Person;
  8. import com.easy.proxy.CGLIB_Proxy;
  9. import com.easy.proxy.JDK_Proxy;
  10. /**
  11. * 包含jdk动态代理和cglib代理的测试
  12. * @author qindongliang
  13. *
  14. */
  15. public class MethodTest {
  16. public static void main(String[] args) throws Exception {
  17. //cglibProxyTest();
  18. jdkProxyTest();
  19. }
  20. /****
  21. * cglib代理测试
  22. */
  23. public static void cglibProxyTest()throws Exception{
  24. CarManager car=new CarManager("大众");
  25. //
  26. // car.run();
  27. // car.stop();
  28. //得到代理类对象
  29. CarManager carManager=CGLIB_Proxy.proxyTarget(car);
  30. carManager.run();
  31. }
  32. /***
  33. * jdk动态代理
  34. */
  35. public static void jdkProxyTest() {
  36. PersonDao user=new PersonDaoImpl();
  37. Class<?> cls=user.getClass();
  38. InvocationHandler handler=new JDK_Proxy(user);
  39. //转换得来的代理对象
  40. PersonDao proxy=(PersonDao)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), handler);
  41. proxy.addUser(new Person("hadoop"));
  42. proxy.deleteUser("lucene");
  43. proxy.updateUser("solr and elasticsearch");
  44. }
  45. }

[java] view plaincopy

  1. package com.easy.main;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Proxy;
  4. import com.easy.dao.PersonDao;
  5. import com.easy.dao.impl.CarManager;
  6. import com.easy.dao.impl.PersonDaoImpl;
  7. import com.easy.model.Person;
  8. import com.easy.proxy.CGLIB_Proxy;
  9. import com.easy.proxy.JDK_Proxy;
  10. /**
  11. * 包含jdk动态代理和cglib代理的测试
  12. * @author qindongliang
  13. *
  14. */
  15. public class MethodTest {
  16. public static void main(String[] args) throws Exception {
  17. //cglibProxyTest();
  18. jdkProxyTest();
  19. }
  20. /****
  21. * cglib代理测试
  22. */
  23. public static void cglibProxyTest()throws Exception{
  24. CarManager car=new CarManager("大众");
  25. //
  26. // car.run();
  27. // car.stop();
  28. //得到代理类对象
  29. CarManager carManager=CGLIB_Proxy.proxyTarget(car);
  30. carManager.run();
  31. }
  32. /***
  33. * jdk动态代理
  34. */
  35. public static void jdkProxyTest() {
  36. PersonDao user=new PersonDaoImpl();
  37. Class<?> cls=user.getClass();
  38. InvocationHandler handler=new JDK_Proxy(user);
  39. //转换得来的代理对象
  40. PersonDao proxy=(PersonDao)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), handler);
  41. proxy.addUser(new Person("hadoop"));
  42. proxy.deleteUser("lucene");
  43. proxy.updateUser("solr and elasticsearch");
  44. }
  45. }

测试JDK动态代理结果:

测试cglib代理结果:

总结:使用代理模式,在一些场景,非常灵活,而且无侵入式的发挥巨大的作用,这就是面向切面编程的核心思想。 参考文章: 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

本文分享自微信公众号 - 我是攻城师(woshigcs)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2015-10-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • SparkStreaming如何优雅的停止服务

    我是攻城师
  • 万法归宗之Hadoop编程无界限

    我是攻城师
  • 在Java里面如何解决进退两难的jar包冲突问题?

    es api组件依赖guava18.0,spark项目由于业务需要写入es所以需要依赖es ,但spark项目的环境又需要依赖guava14.0,如果换成高版本...

    我是攻城师
  • Spring框架系列(二)之Bean的注解管理

    微信公众号:compassblog 欢迎关注、转发,互相学习,共同进步! 有任何问题,请后台留言联系! 1、Spring中的两种容器 在系列(一)中我们已经知道...

    compassblog
  • (四)SpringBoot2.0基础篇- 多数据源,JdbcTemplate和JpaRepository

  • Spring Boot+JPA+Mysql完成数据库整合操作

    Spring Boot结合JPA操作Mysql数据库十分方便,可以做到零配置文件。具体流程如下。

    itlemon
  • SpringData【Spring整合Hibernate】

      在resources目录下创建spring的配置文件和数据库连接的属性文件,如下:

    用户4919348
  • Spring之动态注册bean

    如我之前做个的一个支持扫表的基础平台,使用者只需要添加基础配置 + Groovy任务,就可以丢到这个平台上面来运行了,而这个基础平台是一直都在运行的,所以在新来...

    一灰灰blog
  • 史上最简单的JPA关联教程

    我们这边接着上一节的课程继续介绍,这边我新建了Goods,GoodsDetail,Classify,Address四个实体映射类。分别进行一对一,一对多,多对...

    林老师带你学编程
  • Java代理设计模式(Proxy)的四种具体实现:静态代理和动态代理

    面试问题:Java里的代理设计模式(Proxy Design Pattern)一共有几种实现方式?这个题目很像孔乙己问“茴香豆的茴字有哪几种写法?”

    Jerry Wang

扫码关注云+社区

领取腾讯云代金券