前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >重温java代理模式

重温java代理模式

作者头像
我是攻城师
发布2018-05-14 10:59:40
4430
发布2018-05-14 10:59:40
举报
文章被收录于专栏:我是攻城师我是攻城师

文章关键词: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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2015-10-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 我是攻城师 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
Elasticsearch Service
腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档