spring aop

来源:互联网 发布:dnf账号数据出现异常 编辑:程序博客网 时间:2024/05/29 14:10

本人初学aop,刚学时可能会被里面专业的词语(通知,连接点,切入点,切面。。。)搞得晕头转向,其实个人觉得最好的方法还是通过例子学习。

个人理解,AOP简单的说就是将与业务或者主流程无关的代码剥离出来,降低耦合,这样核心代码更加突出,不会穿插很多与业务无关的代码,比如日志模块等。


拿《Spring in Action》里的经典例子来做解释,比如一个演奏家在演奏音乐,在演奏前观众要就坐,关掉手机,演奏高潮时观众要鼓掌。如果我们正常编程序,可能在编写演奏家演奏音乐时(perform())得穿插进观众的程序,即演奏家演奏音乐时,还得忙着指导观众来鼓掌,如下面程序所示:


public void perform(){    audience.takeSeats();    audience.turnOffCellPhones();    System.out.println("Perform");    audience.applaud();}


我们可能会经常这样编程序,但仔细想一想,演奏家是不是应该专心致志表演,不应该关心观众是否鼓掌。观众应该主动根据演奏家的表演做出反应,而不是根据演奏家的要求。也就是说观众应该主动的去执行,而不是被动的执行。

先看下面演奏者的程序:


public interface Performer {public void perform();}


@Componentpublic class Instrumentalist implements Performer{@Overridepublic void perform() {System.out.println("Perform.");}}


上面定义了演奏者的动作(perform()),这个也是演奏者的主要负责的事情,没有穿插进观众的动作。那么观众应该如何加入进来呢?这时候就用到AOP了,


再贴出一段程序:


@Aspect@Componentpublic class Audience {@Pointcut("execution(* *.perform(..))")public void performance(){};@Before("performance()")public void takeSeats(){System.out.println("Take Seats.");}@Before("performance()")public void turnOffCellPhones(){System.out.println("Turn off CellPhones.");}@AfterReturning("performance()")public void applaud(){System.out.println("Applaud");}public void demandRefund(){System.out.println("demandRefund");}}


这里的观众其实就是一个切面(@Aspect),切面包括了通知(Advice)和切入点(Pointcut),他们组合起来完整的表达了功能,何时何地完成其功能。


切入点定义了“何地”,就是通知要织入的一个或多个连接点,一般是明确的类和方法或者用正则表达式匹配,这里的

@PointCut就相当于切入点,execution(* *.perform(..))中的execution表示执行方法时,第一个*代表任意返回类型,第二个*代表任意类,perform代表perform方法,(..)代表任意参数类型。合起来代表在任意返回类型,任意参数类型的peform()方法中进行切入,即将观众这个切面切入到perform() 方法中。


通知定义了切面的“什么”和“何时使用”,在某个方法被调用之前?之后?之前和之后?这里的@before和@AfterReturning就相当于通知,表示在perform()执行之前和返回之后执行。


这样从代码上,观众与演奏家完全解耦,却可以实现同样的功能。

代码结构如下:




Spring的配置文件如下:

application.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"xmlns:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"default-autowire="byName"><context:annotation-config></context:annotation-config><context:component-scan base-package="net.csdn.aop"></context:component-scan><aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>

测试程序如下:

public class Main {public static void main(String[] args){ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");ctx.getBean(Performer.class).perform();}}



结果输出如下:



这就是一个简单的测试用例,当然,也可以不使用注解,把其中的注解全部去掉,全部在XML中配置,如下:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"xmlns:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"default-autowire="byName">        <bean id="instrumentalist" class="net.csdn.aop.Instrumentalist"></bean><bean id="audience" class="net.csdn.aop.Audience"></bean><aop:config><aop:aspect ref="audience"><aop:before method="takeSeats" pointcut="execution(* *.perform(..))"/><aop:before method="turnOffCellPhones" pointcut="execution(* *.perform(..))"/><aop:after-returning method="applaud" pointcut="execution(* *.perform(..))"/></aop:aspect></aop:config></beans>


个人比较喜欢用注解,两种方式可以各选其一~




原创粉丝点击