AOP的作用这里就不再作说明了,下面开始讲解一个很简单的入门级例子。
引用一个猴子偷桃,守护者守护果园抓住猴子的小情节。
猴子偷桃类(普通类):
package com.samter.common;
/**
* 猴子
* @author Administrator
*
*/
public class Monkey {
public void stealPeaches(String name){
System.out.println("【猴子】"+name+"正在偷桃...");
}
}
守护者类(声明为Aspect):
package com.samter.aspect;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* 桃园守护者
* @author Administrator
*
*/
@Aspect
public class Guardian {
@Pointcut("execution(* com.samter.common.Monkey.stealPeaches(..))")
public void foundMonkey(){}
@Before(value="foundMonkey()")
public void foundBefore(){
System.out.println("【守护者】发现猴子正在进入果园...");
}
@AfterReturning("foundMonkey() && args(name,..)")
public void foundAfter(String name){
System.out.println("【守护者】抓住了猴子,守护者审问出了猴子的名字叫“"+name+"”...");
}
}
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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
>
<!-- 定义Aspect -->
<bean id="guardian" class="com.samter.aspect.Guardian" />
<!-- 定义Common -->
<bean id="monkey" class="com.samter.common.Monkey" />
<!-- 启动AspectJ支持 -->
<aop:aspectj-autoproxy />
</beans>
测试类:
package com.samter.common;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
Monkey monkey = (Monkey) context.getBean("monkey");
try {
monkey.stealPeaches("孙大圣的大徒弟");
}
catch(Exception e) {}
}
}
控制台输出:
【守护者】发现猴子正在进入果园…
【猴子】孙大圣的大徒弟正在偷桃…
【守护者】抓住了猴子,守护者审问出了猴子的名字叫“孙大圣的大徒弟”…
- 写了一个猴子正在偷桃的方法。
- 写了一个标志为@Aspect的类,它是守护者。它会在猴子偷桃之前发现猴子,并在猴子偷桃之后抓住猴子。
原理:
- @Aspect的声明表示这是一个切面类。
- @Pointcut使用这个方法可以将com.samter.common.Monkey.stealPeaches(..)方法声明为poincut即切入点。作用,在stealPeaches方法被调用的时候执行2的foundMonkey方法。其中execution是匹配方法执行的切入点,也就是spring最常用的切入点定义方式。 @Pointcut切入点的时候,我们改写一下正则表达式,修改为“@Pointcut(“execution(* steal*(..))”)”,意思就是说,针对工程下面所有的类以steal开头的方法都监控。即:我再添加一个大象类,它去偷香蕉(stealBanana)也会被抓。但是猴子类再加一个lookPeaches方法(看桃子)的话,就不会被抓。
- @Before(value=”foundMonkey()”):@Before声明为在切入点方法执行之前执行,而后面没有直接声明切入点,而是value=”foundMonkey()”,是因为如果@afterReturning等都有所改动的时候都必须全部改动,所以统一用Pointcut的foundMonkey代替,这样子有改动的时候仅需改动一个地方。其他@AfterReturning类同。
xml配置文件,里面有具体的注释。
注意
Guardian类里面的
@Pointcut(“execution(*com.samter.common.Monkey.stealPeaches(..))”),如果stealPeaches有参数则..表示所有参数,@AfterReturning(“foundMonkey() && args(name,..)”)的&& args(name,..)可以获取切入点方法stealPeaches的参数。
总结:这里列举了一个简单的例子,但是不难引申到应用中,当你写一个登陆系统的时候,你或许要记录谁成功登陆了系统,谁登陆系统密码错误等等的信息,这样子你用切面是再合适不过的了,总之当你的事务逻辑都设计到日志、安全检查、事务管理等等共同的内容的时候,用切面是要比你没有一个事务逻辑类都有相关代码或者相关引用好得多。
补充
也有把切入点,方法配置到xml里面的
<aop:aspectj-autoproxy />
<aop:config>
<aop:aspect id="logAspect" ref="aspectLogger">
<!--配置com.spring.service包下所有类或接口的所有方法-->
<aop:pointcut id="businessService" expression="execution(* com.company.contract.api.*.*(..))" />
<aop:after pointcut-ref="businessService" method="logQuery"/>
<aop:after-throwing pointcut-ref="businessService" method="logException" throwing="ex"/>
</aop:aspect>
</aop:config>