6月13日,阴转细雨。“人闲桂花落。夜静春山空。

月出惊山鸟。时鸣春涧中。”

无论在面向过程还是在面向对象里,奇妙的“纯”字,似乎永远都充满了无限的可能性。除了函数之所调用、类之所封装,在程序猿文化里,对于“纯粹”的感知和定义。既起自于代码。又超越了代码。也就是说,可以真真切切地感觉到纯净的。不仅是我们的每个Bean和每个Class,还包含每个Coder的心。

然而。客户的需求是千变万化和千奇百怪的,Spring在为Coder在应对和处理各自不同的要求时,提供了一种特殊的解决方案-AOP。在OOP和AOP里,最佳存在方式,并非让当中有某一个显得格外突出。而是OOP和AOP的调和以及平衡,不仅是Spring不断寻求的完美状态,也是每一个Coder所追求的理想境地。

编程语言终于极的目标就是能以更自然。更灵活的方式模拟世界,从原始机器语言到过程语言再到面向对象的语言,编程语言一步步地用更自然,更强大的方式描写叙述软件。

AOPAspect Oriented Programing 的简称。即面向切面编程

尽管AOP作为一项编程技术已经有多年的历史,但一直长时间停顿在学术领域,直到近几年,AOP才作为一项真正的有用技术在应用领域开疆拓土。AOP是软件开发饲养发展到一定阶段的产物,但Aop的出现并非要全然取代OOP。而不过作为OOP的故意补充。须要指出的是AOP的应用场合是受限的,它一般只适合用于那些具有横切逻辑的应用场合:如性能监測,訪问控制,事物管理以及日志记录(尽管非常多解说日志记录的样例用于AOP的解说。但非常多人觉得非常难用AOP编写有用日志。)不过,这丝毫不影响AOP作为一种新的软件开发思想在软件开发领域所占的地位。

以下通过一个简单的样例。一窥AOP的精妙。

1、使用Log4j。我们能够在控制台查看日志信息,观察程序执行过程。

(1)下载log4j.jar,下载链接http://logging.apache.org/log4j/2.x/

(2) 在src以下。编写log4j.properties(网上找一个改一下)

  1. log4j.rootLogger=debug, stdout
  2. log4j.appender.stdout=org.apache.log4j.ConsoleAppender
  3. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
  4. # Pattern to output the caller's file name and line number.
  5. log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n

2、编写一个业务接口文件WatchBall.java

  1. package edu.eurasia.aop;
  2.  
  3. public interface WatchBall {
  4. public void watchfootball(String city);
  5. public void watchbasketball(String city);
  6. }

当中一个方法是看足球,一个是看篮球。

3、编写一个业务实现文件WatchBallImpl.java

  1. package edu.eurasia.aop;
  2.  
  3. import org.apache.log4j.Logger;
  4.  
  5. public class WatchBallImpl implements WatchBall {
  6. Logger logger = Logger.getLogger(this.getClass());
  7.  
  8. @Override
  9. public void watchfootball(String city) {
  10. logger.debug("去 " + city + " 看2014巴西世界杯");
  11. }
  12.  
  13. @Override
  14. public void watchbasketball(String city) {
  15. logger.debug(" 去" + city + " 看2014NBA总决赛");
  16. }
  17. }

实现接口中的方法。在运行watchfootball()和watchbasketball()这些目标对象的方法前后。会织入一些其他业务方法。以下创建这些方法,在运行这些方法前要运行的方法  BeforeAdvice.java 。

4、编写一个切面文件BeforeAdvice.java

  1. package edu.eurasia.aop;
  2.  
  3. import java.lang.reflect.Method;
  4. import org.apache.log4j.Logger;
  5. import org.springframework.aop.MethodBeforeAdvice;
  6.  
  7. public class BeforeAdvice implements MethodBeforeAdvice {
  8. Logger logger = Logger.getLogger(this.getClass());
  9.  
  10. @Override
  11. public void before(Method method, Object[] objects, Object o)
  12. throws Throwable {
  13. logger.debug(" 看球前,先去 " + objects[0] + " 咖啡馆喝杯巴西咖啡 ...");
  14. }
  15. }

在看球前先去咖啡馆喝杯巴西咖啡...

5、编写还有一个切面文件AfterAdvice.java

  1. package edu.eurasia.aop;
  2.  
  3. import java.lang.reflect.Method;
  4.  
  5. import org.apache.log4j.Logger;
  6. import org.springframework.aop.AfterReturningAdvice;
  7.  
  8. public class AfterAdvice implements AfterReturningAdvice {
  9.  
  10. @Override
  11. public void afterReturning(Object o, Method method, Object[] objects,
  12. Object o1) throws Throwable {
  13. Logger logger = Logger.getLogger(this.getClass());
  14.  
  15. logger.debug("看完球去 " + objects[0] + " 麦当劳吃汉堡包!");
  16. }
  17. }

在看完球后去麦当劳吃汉堡包...

     6、编写spring的配置文件applicationContext.xml

  1. <?
  2.  
  3. xml version="1.0" encoding="UTF-8"?
  4.  
  5. >
  6. <beans xmlns="http://www.springframework.org/schema/beans"
  7. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  8. xsi:schemaLocation="http://www.springframework.org/schema/beans
  9. http://www.springframework.org/schema/beans/spring-beans.xsd">
  10.  
  11. <!-- 代理类.调用的时候则是调用这个代理类 -->
  12. <bean id="ball" class="org.springframework.aop.framework.ProxyFactoryBean">
  13. <!-- 代理接口(业务类接口) -->
  14. <property name="proxyInterfaces">
  15. <value>edu.eurasia.aop.WatchBall</value>
  16. </property>
  17. <!-- interceptorNames 属性的list集合里面仅仅能放 通知/通知者 -被称为拦截者(拦截器)。-->
  18. <property name="interceptorNames">
  19. <list>
  20. <value>beforeBallAdvisor</value>
  21. <value>afterBallAdvisor</value>
  22. </list>
  23. </property>
  24. <!-- 业务实现类 -->
  25. <property name="target">
  26. <ref bean="ballTarget"></ref>
  27. </property>
  28. </bean>
  29.  
  30. <!-- 通用正則表達式切入点 -->
  31. <bean id="beforeBallAdvisor"
  32. class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  33. <!-- 须要对那些方法进行拦截 -->
  34. <property name="advice" ref="beforeBallAdvice"></property>
  35. <property name="pattern" value=".*.*foot.*"></property>
  36. </bean>
  37.  
  38. <!-- 通用正則表達式切入点 -->
  39. <bean id="afterBallAdvisor"
  40. class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  41. <!-- 须要对那些方法进行拦截 -->
  42. <property name="advice" ref="afterBallAdvice"></property>
  43. <property name="pattern" value=".*.*basket.*"></property>
  44. </bean>
  45.  
  46. <!-- 业务实现 -->
  47. <bean id="ballTarget" class="edu.eurasia.aop.WatchBallImpl"></bean>
  48. <!-- 切面类 -->
  49. <bean id="beforeBallAdvice" class="edu.eurasia.aop.BeforeAdvice"></bean>
  50. <!-- 切面类 -->
  51. <bean id="afterBallAdvice" class="edu.eurasia.aop.AfterAdvice"></bean>
  52. </beans>

这个配置文件是AOP的核心。重点讲解一下。

首先,建立了一个“ball”的bean。这是一个代理bean,由于spring AOP是基于代理的。在里面有代理接口属性。接口能够多个,能够用<list>来表示,本例仅仅有一个就是WatchBall。

interceptorNames属性,这是一个拦截器属性,就是訪问者,在运行目标对象方法时。进行拦截。目标(target)属性对象,就是运行这个对象的方法时,在其前、后再织入一些其他的业务方法。

本例的訪问者是beforeBallAdvisor和afterBallAdvisor,訪问者定义了通知对象。以及通知何时和何地进行訪问target的问题。以beforeBallAdvisor为例。其定义的“通知”是advice,这个advice定义了在业务方法之前运行一些逻辑(何时)。pattern则通过正則表達式,能够知道在不论什么业务(.*.*)方法(何地)运行时,都触发advice。

拦截器bean。先看beforeBallAdvisor,当中pattern是一个正則表達式,说明对WatchBall对象的方法中含有footkeyword则运行beforeBallAdvice这个对象的方法。

afterBallAdvisor是运行target目标方法之后运行的方法。通过正則表達式(<property name="pattern" value=".*.*basket.*">)能够看出,target对象的方法中含有basketkeyword。都要运行这种方法。

7、编写測试类TestBall.java

  1. package edu.eurasia.aop;
  2.  
  3. import org.apache.log4j.Logger;
  4. import org.junit.After;
  5. import org.junit.Before;
  6. import org.junit.Test;
  7. import org.springframework.context.ApplicationContext;
  8. import org.springframework.context.support.ClassPathXmlApplicationContext;
  9.  
  10. public class TestBall {
  11. static Logger logger = Logger.getLogger(TestBall.class);
  12.  
  13. @Test
  14. public void testball() {
  15.  
  16. logger.debug("test begin ");
  17.  
  18. ApplicationContext ctx = new ClassPathXmlApplicationContext(
  19. "applicationContext.xml");
  20. // 这里写的必须是代理类
  21. WatchBall watchball = (WatchBall) ctx.getBean("ball");
  22.  
  23. watchball.watchfootball("里约热内卢");
  24.  
  25. logger.debug("----------------------------");
  26.  
  27. watchball.watchbasketball("德克萨斯州");
  28. }
  29. }

8、执行结果和环境配置

执行结果例如以下:

DEBUG [main] (BeforeAdvice.java:13) -  看球前,先去  里约热内卢  咖啡馆喝杯巴西咖啡 ...

         DEBUG [main] (WatchBallImpl.java:10) - 去 里约热内卢 看2014巴西世界杯

         DEBUG [main] (TestBall.java:34) - ----------------------------

         DEBUG [main] (WatchBallImpl.java:15) -  去德克萨斯州 看2014NBA总决赛

         DEBUG [main] (AfterAdvice.java:15) - 看完球去  德克萨斯州  麦当劳吃汉堡包。

本例使用spring 2.5.6。仅仅需找出spring.jar。commons-logging-1.1.1.jar两个jar包,外加一个log4j.jar就可以。

文件夹结构例如以下:

9、改进一下

上述样例的配置文件中面,代理类ProxyFactoryBean的配置显得啰嗦。Advisor已经把AOP所控制的东西都描写叙述了吗,advice描写叙述了“何时”触发target的对象(before、after、throw等)。pattern描写叙述了“何地”触发的问题(正則表達式)。为什么还要有ProxyFactoryBean呢?怎样解决?

Spring提供了BeanPostProcessor的一个方便实现:DefaultAdvisorAutoProxyCreator。它会自己主动检查訪问者(advisor)的切点是否匹配Bean方法。而且用使用通知的代理来替换这个bean的定义。

这样,将applicationContext.xml改为以下就可以:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd">
  6.  
  7. <!-- 自己主动应用于当前容器中的advisor,不须要定义指定目标Bean的名字字符串 -->
  8. <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
  9.  
  10. <!-- 通用正則表達式切入点 -->
  11. <bean id="beforeBallAdvisor"
  12. class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  13. <!-- 须要对那些方法进行拦截 -->
  14. <property name="advice" ref="beforeBallAdvice"></property>
  15. <property name="pattern" value=".*.*foot.*"></property>
  16. </bean>
  17.  
  18. <!-- 通用正則表達式切入点 -->
  19. <bean id="afterBallAdvisor"
  20. class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  21. <!-- 须要对那些方法进行拦截 -->
  22. <property name="advice" ref="afterBallAdvice"></property>
  23. <property name="pattern" value=".*.*basket.*"></property>
  24. </bean>
  25.  
  26. <!-- 业务实现 -->
  27. <!-- <bean id="ballTarget" class="edu.eurasia.aop.WatchBallImpl"></bean> -->
  28. <bean id="ball" class="edu.eurasia.aop.WatchBallImpl"></bean>
  29. <!-- 切面类 -->
  30. <bean id="beforeBallAdvice" class="edu.eurasia.aop.BeforeAdvice"></bean>
  31. <!-- 切面类 -->
  32. <bean id="afterBallAdvice" class="edu.eurasia.aop.AfterAdvice"></bean>
  33. </beans>

第二十八天 月出惊山鸟 —Spring的AOP的更多相关文章

  1. Spring的AOP与代理

    spring 支持两种注入方式: setter/constructor 支持多种配置方式: xml/java5注解/java类配置 支持两种事务管理: 声明性/编程性 实际上上述方式只有一个就能保证系 ...

  2. 二十9天 月出冲击黑鸟 —Spring的AOP_AspectJ @annotation

    6月14日,阴转雨. "四面垂杨十里荷,向云何处最花多, 画楼南畔夕阳和.天气乍凉人寂寞, 光阴须得酒消磨,且来花里听笙歌." 面向切面的框架AspectJ邂逅Spring,不仅造 ...

  3. 一步一步深入spring(5)--使用基于注解的spring实现 AOP

    1.要利用spring aop,至少需要添加以下jar包 使用spring需要的jarspring.jar .commons-logging.jar 使用切面编程(AOP)需要的jar aspectj ...

  4. spring(二) AOP之AspectJ框架的使用

    前面讲解了spring的特性之一,IOC(控制反转),因为有了IOC,所以我们都不需要自己new对象了,想要什么,spring就给什么.而今天要学习spring的第二个重点,AOP.一篇讲解不完,所以 ...

  5. 框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)

    一.AOP的核心概念回顾 https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#a ...

  6. 深入浅析Spring的AOP实现原理

    转载来源:https://www.jb51.net/article/81788.htm AOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-Or ...

  7. spring框架 AOP核心详解

    AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Asp ...

  8. 记一次Spring的aop代理Mybatis的DAO所遇到的问题

    由来 项目中需要实现某个订单的状态改变后然后推送给第三方的功能,由于更改状态的项目和推送的项目不是同一个项目,所以为了不改变原项目的代码,我们考虑用spring的aop来实现. 项目用的是spring ...

  9. Spring中AOP实现

    1.什么是SpringAOP 什么是aop:Aspect Oriented Programming的缩写,面向切面编程,通过预编译和动态代理实现程序功能的 统一维护的一种技术 主要功能:日志记录,性能 ...

随机推荐

  1. C++中的namespace详解

    原文链接:http://blog.csdn.net/yao_zhuang/article/details/1853625 namespace中文意思是命名空间或者叫名字空间,传统的C++只有一个全局的 ...

  2. 在Windows下如何创建指定的虚拟环境

    前几天给大家分享了如何在默认的情况下创建虚拟环境,没来得及上车的伙伴,可以戳这篇文章:在Windows下如何创建虚拟环境(默认情况下).今天小编给大家分享一下,如何创建的指定的Python环境. 创建 ...

  3. iscsi共享存储的简单配置和应用

    1.环境介绍 SCSI(Small Computer System Interface)是块数据传输协议,在存储行业广泛应用,是存储设备最基本的标准协议.从根本上说,iSCSI协议是一种利用IP网络来 ...

  4. C# textBox控件只允许为数字和小数点并且提取出这个数字

    一. textBox控件实现只允许为数字和小数点 如下图所示,在textBox控件框内输入只能是 要在textBox控件属性设置按键按下的事件触发,如下图所示: 二.源代码 textBox控件只允许为 ...

  5. 【Eclipse中使用Git之一】把远程仓库的项目,clone到eclipse里面

    [Eclipse中使用Git之一]把远程仓库的项目,clone到eclipse里面 2015-01-29 19:25 15779人阅读 评论(1) 收藏 举报 .embody{ padding:10p ...

  6. [Python] Wikipedia Crawler

    import time import urllib import bs4 import requests start_url = "https://en.wikipedia.org/wiki ...

  7. React Native入门——IDE及其它相关基础技术

    关于React Native的开发,当中一个问题是缺少好用的IDE,有些人说不就是JS么,搞一个记事本也就写了,那样尽管牛逼,但事实上还是非常头大的,有一款好的IDE还是能提升开发效率的,这里对几个还 ...

  8. 4.2.2 MINUS

    4.2.2 MINUS正在更新内容,请稍后

  9. iOS Core Animation具体解释(四)AutoLayout中的动画

    原创blog.转载请注明出处 blog.csdn.net/hello_hwc 欢迎关注我的iOS SDK具体解释专栏 http://blog.csdn.net/column/details/huang ...

  10. nginx最新配置

    #user  nobody;worker_processes  1; #error_log  logs/error.log;#error_log  logs/error.log  notice;#er ...