spring aop

本人初学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();
}


@Component
public class Instrumentalist implements Performer{

	@Override
	public void perform() {
		System.out.println("Perform.");
		
	}
	
}


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


再贴出一段程序:


@Aspect
@Component
public 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.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
	http://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.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
	http://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>


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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值