AOP示例(再续)

java.lang.reflect.Proxy 、java.lang.reflect.InvocationHandler

不知道怎么去解释了,如果使用Proxy 获取一个类的实例,那么在调用这个类的方法前会先执行InvocationHandler 的invoke方法,那么我们就可以利用这个特性来实现自己的AOP了,下面的例子将介绍如何实现Spring 中AOP的前通知、后通知和环绕通知。实现思路如下:

1.DynaProxy动态代理类实现接口InvocationHandler,getBean方法 返回要代理的类,(这个类必须是基于接口的),invoke方法被代理的类执行其方法前一定要调用的方法,在这个方法里面可以在控制被调用的方法是否执行,或者做点其他事情。写日志,性能计算,权限控制等,setMethodAdvice方法,绑定自己定义的通知类。

2.MethodAdvice,加载自己定义的消息通知。目前支持前通知,后通知,和环绕通知,要实现这个三个功能只需要实现对应的接口,(^_^这些接口也是我自己定义的),然后通用方法AddAdvice加载进去,这里支持多个消息通知,对于多个消息通知执行的顺序是环绕通知,前通知,后通知。

3.定义了四个接口Advice、AroundAdvice、BeforeAdvice、AfterAdvice

4.实现3个Advice的实现类,分别对应环绕通知,前通知,后通知。

5.实现自己的消息通知类MyAdvice

6.编写测试类Test

下面看具体的代码实现

  1. /**
  2. *
  3. */
  4. packagecom.advice;
  5. importjava.lang.reflect.InvocationHandler;
  6. importjava.lang.reflect.Method;
  7. importjava.lang.reflect.Proxy;
  8. /**
  9. *@authorzjb
  10. *
  11. */
  12. publicclassDynaProxyimplementsInvocationHandler{
  13. privateMethodAdvicemethodAdvice;
  14. privateObjectdelegate;
  15. @Override
  16. publicObjectinvoke(Objectporxy,Methodmethod,Object[]args)
  17. throwsThrowable{
  18. methodAdvice.setArgs(args);
  19. methodAdvice.setMethod(method);
  20. methodAdvice.setProxy(this);
  21. methodAdvice.setPos(-1);
  22. methodAdvice.setDone(false);
  23. returnmethodAdvice.proceed();
  24. }
  25. publicObjectgetBean(StringclassName){
  26. try{
  27. delegate=Class.forName(className).newInstance();
  28. methodAdvice.setTarget(delegate);
  29. returnProxy.newProxyInstance(
  30. delegate.getClass().getClassLoader(),
  31. delegate.getClass().getInterfaces(),this);
  32. }catch(Exceptione){
  33. e.printStackTrace();
  34. }
  35. returnnull;
  36. }
  37. publicMethodAdvicegetMethodAdvice(){
  38. returnmethodAdvice;
  39. }
  40. publicvoidsetMethodAdvice(MethodAdvicemethodAdvice){
  41. this.methodAdvice=methodAdvice;
  42. }
  43. }
  1. packagecom.advice;
  2. importjava.lang.reflect.InvocationTargetException;
  3. importjava.lang.reflect.Method;
  4. importjava.util.ArrayList;
  5. importjava.util.List;
  6. importcom.advice.impl.AfterAdviceImpl;
  7. importcom.advice.impl.AroundAdviceImpl;
  8. importcom.advice.impl.BeforeAdviceImpl;
  9. publicclassMethodAdvice{
  10. privateList<Advice>adviceList=newArrayList<Advice>();
  11. privateObjecttarget;
  12. privateMethodmethod;
  13. privateObject[]args;
  14. privateintpos=-1;
  15. privatebooleandone;
  16. privateDynaProxyproxy;
  17. publicvoidAddAdvice(Object[]advices){
  18. adviceList.clear();
  19. List<Advice>aroundAdvice=newArrayList<Advice>();
  20. List<Advice>beforeAdvice=newArrayList<Advice>();
  21. List<Advice>afterAdvice=newArrayList<Advice>();
  22. for(Objecto:advices){
  23. if(oinstanceofAroundAdvice){
  24. AroundAdviceImpltemp=newAroundAdviceImpl((AroundAdvice)o);
  25. aroundAdvice.add(temp);
  26. }
  27. if(oinstanceofBeforeAdvice){
  28. BeforeAdviceImplba=newBeforeAdviceImpl((BeforeAdvice)o);
  29. beforeAdvice.add(ba);
  30. }
  31. if(oinstanceofAfterAdvice){
  32. AfterAdviceImplaa=newAfterAdviceImpl((AfterAdvice)o);
  33. afterAdvice.add(aa);
  34. }
  35. }
  36. adviceList.addAll(aroundAdvice);
  37. adviceList.addAll(beforeAdvice);
  38. adviceList.addAll(afterAdvice);
  39. }
  40. publicObjectproceed(){
  41. pos++;
  42. if(pos>=adviceList.size()&&!done){
  43. returninvoke();
  44. }
  45. Objecto=null;
  46. //如果执行到后通知了,那就去执行目标方法
  47. if(!done&&adviceList.get(pos)instanceofAfterAdvice){
  48. o=invoke();
  49. }
  50. adviceList.get(pos).invoke(this);
  51. returno;
  52. }
  53. privateObjectinvoke(){
  54. done=true;
  55. try{
  56. returnmethod.invoke(target,args);
  57. }catch(IllegalArgumentExceptione){
  58. //TODOAuto-generatedcatchblock
  59. e.printStackTrace();
  60. }catch(IllegalAccessExceptione){
  61. //TODOAuto-generatedcatchblock
  62. e.printStackTrace();
  63. }catch(InvocationTargetExceptione){
  64. //TODOAuto-generatedcatchblock
  65. e.printStackTrace();
  66. }
  67. returnnull;
  68. }
  69. publicDynaProxygetProxy(){
  70. returnproxy;
  71. }
  72. publicvoidsetProxy(DynaProxyproxy){
  73. this.proxy=proxy;
  74. }
  75. publicvoidsetTarget(Objecttarget){
  76. this.target=target;
  77. }
  78. publicvoidsetArgs(Object[]args){
  79. this.args=args;
  80. }
  81. publicvoidsetMethod(Methodmethod){
  82. this.method=method;
  83. }
  84. publicObjectgetTarget(){
  85. returntarget;
  86. }
  87. publicMethodgetMethod(){
  88. returnmethod;
  89. }
  90. publicObject[]getArgs(){
  91. returnargs;
  92. }
  93. publicintgetPos(){
  94. returnpos;
  95. }
  96. publicvoidsetPos(intpos){
  97. this.pos=pos;
  98. }
  99. publicbooleanisDone(){
  100. returndone;
  101. }
  102. publicvoidsetDone(booleandone){
  103. this.done=done;
  104. }
  105. }
  1. packagecom.advice;
  2. publicinterfaceAdvice{
  3. publicObjectinvoke(MethodAdvicemethodAdvice);
  4. }
  1. packagecom.advice;
  2. publicinterfaceAroundAdviceextendsAdvice{
  3. }
  1. packagecom.advice;
  2. importjava.lang.reflect.Method;
  3. publicinterfaceBeforeAdvice{
  4. publicvoidbefore(Methodm,Object[]args,Objecttarget);
  5. }
  1. packagecom.advice;
  2. importjava.lang.reflect.Method;
  3. publicinterfaceAfterAdvice{
  4. publicvoidafter(Methodm,Object[]args,Objecttarget);
  5. }
  1. packagecom.advice.impl;
  2. importcom.advice.Advice;
  3. importcom.advice.MethodAdvice;
  4. publicclassAroundAdviceImplimplementsAdvice{
  5. privateAdviceadvice;
  6. @SuppressWarnings("unused")
  7. privateAroundAdviceImpl(){};
  8. publicAroundAdviceImpl(Adviceadvice){
  9. this.advice=advice;
  10. }
  11. @Override
  12. publicObjectinvoke(MethodAdvicemethodAdvice){
  13. returnadvice.invoke(methodAdvice);
  14. }
  15. }
  1. packagecom.advice.impl;
  2. importcom.advice.Advice;
  3. importcom.advice.BeforeAdvice;
  4. importcom.advice.MethodAdvice;
  5. publicclassBeforeAdviceImplimplementsAdvice{
  6. privateBeforeAdvicebeforeAdvice;
  7. @SuppressWarnings("unused")
  8. privateBeforeAdviceImpl(){
  9. }
  10. publicBeforeAdviceImpl(BeforeAdvicebeforeAdvice){
  11. this.beforeAdvice=beforeAdvice;
  12. }
  13. @Override
  14. publicObjectinvoke(MethodAdvicemethodAdvice){
  15. beforeAdvice.before(methodAdvice.getMethod(),methodAdvice.getArgs(),methodAdvice.getTarget());
  16. returnmethodAdvice.proceed();
  17. }
  18. }

  1. packagecom.advice.impl;
  2. importcom.advice.Advice;
  3. importcom.advice.AfterAdvice;
  4. importcom.advice.MethodAdvice;
  5. publicclassAfterAdviceImplimplementsAdvice{
  6. privateAfterAdviceafterAdvice;
  7. @SuppressWarnings("unused")
  8. privateAfterAdviceImpl(){}
  9. publicAfterAdviceImpl(AfterAdviceafterAdvice){
  10. this.afterAdvice=afterAdvice;
  11. }
  12. @Override
  13. publicObjectinvoke(MethodAdvicemethodAdvice){
  14. ObjectretVal=methodAdvice.proceed();
  15. afterAdvice.after(methodAdvice.getMethod(),methodAdvice.getArgs(),methodAdvice.getTarget());
  16. returnretVal;
  17. }
  18. }
  1. packagecom.myadvice.test;
  2. importjava.lang.reflect.Method;
  3. importjava.util.Arrays;
  4. importbsh.EvalError;
  5. importbsh.Interpreter;
  6. importcom.advice.AfterAdvice;
  7. importcom.advice.AroundAdvice;
  8. importcom.advice.BeforeAdvice;
  9. importcom.advice.MethodAdvice;
  10. publicclassMyAdviceimplementsBeforeAdvice,AfterAdvice,AroundAdvice{
  11. /**
  12. *后通知
  13. */
  14. @Override
  15. publicvoidafter(Methodm,Object[]args,Objecttarget){
  16. System.out.println("后通知,调用的方法:"+m.getName()+",参数:"+Arrays.toString(args));
  17. }
  18. /**
  19. *环绕通知,最维强大的通知,可以控制目标方法是否执行,也可以改变方法的返回值
  20. */
  21. @Override
  22. publicObjectinvoke(MethodAdvicemethodAdvice){
  23. System.out.println("[环绕通知]");
  24. /**
  25. *这里我们禁止李四发表任何的评论
  26. */
  27. if(methodAdvice.getMethod().getName().equals("comment")"李四".equals(methodAdvice.getArgs()[0])){
  28. System.out.println("屏蔽李四所有的评论");
  29. StringreturnType=methodAdvice.getMethod().getReturnType().getName();
  30. if("int".equals(returnType)||"long".equals(returnType)||"float".equals(returnType)||"double".equals(returnType)||"byte".equals(returnType)||"short".equals(returnType)){
  31. //利用BeanShell构造一个内置变量返回,这里想了好久,没有想到什么方法可以根据
  32. //指定数据类型返回指定的变量
  33. Interpreteri=newInterpreter();
  34. try{
  35. returni.eval("("+returnType+")0");
  36. }catch(EvalErrore){
  37. //TODOAuto-generatedcatchblock
  38. e.printStackTrace();
  39. }
  40. }elseif("boolean".equals(returnType)){
  41. returnfalse;
  42. }
  43. returnnull;
  44. }else{
  45. returnmethodAdvice.proceed();
  46. }
  47. }
  48. /**
  49. *前通知
  50. */
  51. @Override
  52. publicvoidbefore(Methodm,Object[]args,Objecttarget){
  53. System.out.println("前通知,调用的方法:"+m.getName()+",参数:"+Arrays.toString(args));
  54. }
  55. }
  1. packagecom.myadvice.test;
  2. importcom.advice.DynaProxy;
  3. importcom.advice.MethodAdvice;
  4. importcom.test.BookBiz;
  5. importcom.test.BookBizImpl;
  6. publicclassTest{
  7. /**
  8. *@paramargs
  9. */
  10. publicstaticvoidmain(String[]args){
  11. DynaProxyproxy=newDynaProxy();
  12. MethodAdvicemethodAdvice=newMethodAdvice();
  13. methodAdvice.AddAdvice(newObject[]{newMyAdvice()});
  14. proxy.setMethodAdvice(methodAdvice);
  15. BookBizbookBiz=(BookBiz)proxy.getBean(BookBizImpl.class.getName());
  16. bookBiz.buy("张三","Spring深入潜出",50);
  17. bookBiz.comment("李四","《恐怖世界》一点都不恐怖,很好看!");
  18. bookBiz.comment("张三","《Spring深入潜出》还是写得不错的!");
  19. }
  20. }

运行Test类得到下面的结果:

[环绕通知]
前通知,调用的方法:buy,参数:[张三, Spring深入潜出, 50.0]
业务方法buy开始执行
·张三购买图书:Spring深入潜出
·张三增加积分:5
·向物流系统下发货单
业务方法buy结束
后通知,调用的方法:buy,参数:[张三, Spring深入潜出, 50.0]
[环绕通知]
屏蔽李四所有的评论
[环绕通知]
前通知,调用的方法:comment,参数:[张三, 《Spring深入潜出》还是写得不错的!]
业务方法comment开始执行
·张三发表书评《Spring深入潜出》还是写得不错的!
业务方法comment结束
后通知,调用的方法:comment,参数:[张三, 《Spring深入潜出》还是写得不错的!]
从结果可以看出和使用spring的一样。

这个又个小小的问题,为什么spring里面前通知后通知的接口方法要包含Object object, Method method这两个参数,如果又这里两个参数那么就可以在前后通知里面去执行目标方法了,这样不是很好。还有就是使用jdk的代理,被代理的类都必须是基于接口的,重要也不是很方便,如果使用cglib动态代理类,那么被代理的类就可以不是基于接口的了,这样比较方便,下一篇将介绍如何使用cglib动态代理

潮汐研究作为海洋科学的关键分支,融合了物理海洋学、地理信息系统及水利工程等多领域知识。TMD2.05.zip是一套基于MATLAB环境开发的潮汐专用分析工具集,为科研人员与工程实践者提供系统化的潮汐建模与计算支持。该工具箱通过模块化设计实现了两大核心功能: 在交互界面设计方面,工具箱构建了图形化操作环境,有效降低了非专业用户的操作门槛。通过预设参数输入模块(涵盖地理坐标、时间序列、测站数据等),用户可自主配置模型运行条件。界面集成数据加载、参数调整、可视化呈现及流程控制等标准化组件,将复杂的数值运算过程转化为可交互的操作流程。 在潮汐预测模块中,工具箱整合了谐波分解法与潮流要素解析法等数学模型。这些算法能够解构潮汐观测数据,识别关键影响要素(包括K1、O1、M2等核心分潮),并生成不同时间尺度的潮汐预报。基于这些模型,研究者可精准推算特定海域的潮位变化周期与振幅特征,为海洋工程建设、港湾规划设计及海洋生态研究提供定量依据。 该工具集在实践中的应用方向包括: - **潮汐动力解析**:通过多站点观测数据比对,揭示区域主导潮汐成分的时空分布规律 - **数值模型构建**:基于历史观测序列建立潮汐动力学模型,实现潮汐现象的数字化重构与预测 - **工程影响量化**:在海岸开发项目中评估人工构筑物对自然潮汐节律的扰动效应 - **极端事件模拟**:建立风暴潮与天文潮耦合模型,提升海洋灾害预警的时空精度 工具箱以"TMD"为主程序包,内含完整的函数库与示例脚本。用户部署后可通过MATLAB平台调用相关模块,参照技术文档完成全流程操作。这套工具集将专业计算能力与人性化操作界面有机结合,形成了从数据输入到成果输出的完整研究链条,显著提升了潮汐研究的工程适用性与科研效率。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值