- Spring中通过切入点表达式定义具体切入点,其常用AOP切入点表达式定义
指示符 | 作用 |
bean | 用于匹配指定bean id的的方法执行 |
within
| 用于匹配指定包名下类型内的方法执行 |
@annotation | 用于匹配指定注解修饰的方法执行 |
execution | 用于进行细粒度方法匹配执行具体业务 |
- bean
bean("userServiceImpl")) | 指定一个类 |
bean("*ServiceImpl") | 指定所有的后缀为serviceImpl的类 |
- within应用于类级别,实现粗粒度的切面表达式定义:
within("aop.service.UserServiceImpl") | 指定类,只能指定一个类 |
within("aop.service.*") | 只包括当前目录下的类 |
within("aop.service..*") | 指定当前目录包含所有子目录中的类 |
- execution方法级别,细粒度的控制:语法:execution(返回值类型 包名.类名.方法名(参数列表))
execution(void aop.service.UserServiceImpl.addUser()) | 匹配方法 |
execution(void aop.service.PersonServiceImpl.addUser(String)) | 方法参数必须为字符串 |
execution(* aop.service..*.*(..)) | 万能配置 |
- @annotaion应用于方法级别,实现细粒度的控制:
@annotation(com..anno.RequestLog)) | 指定一个需要实现增强功能的方法 |
- execution 实例:专辑有多首歌,播放每首歌后会显示这首歌的播放次数。
一.配置类实现
1.接口
package com.qhf.aop.example04;
public interface CD {
void play(int i);
}
2.实现类:空白CD
package com.qhf.aop.example04;
import java.util.List;
public class BlankCD implements CD {
private String title;//专辑名称
private String artist;//歌手
private List<String> list;//歌曲
public void setTitle(String title) {
this.title = title;
}
public void setArtist(String artist) {
this.artist = artist;
}
public void setList(List<String> list) {
this.list = list;
}
@Override
public void play(int i) {
try {
String song = list.get(i);
System.out.print("Playing '" + song + "' by " + artist + "; ");
} catch (Throwable e){
System.out.print("抛异常; ");
throw e;//必须抛出后才会执行@AfterThrowing
}
}
}
3.配置类,bean实例化返回一个艾薇儿的专辑
package com.qhf.aop.example04;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import java.util.ArrayList;
import java.util.List;
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
@Bean
public BlankCD avrilCD(){
BlankCD b = new BlankCD();
b.setArtist("avril");
b.setTitle("Head above water");
List<String> list = new ArrayList<>();
list.add("Head above water");
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
b.setList(list);
return b;
}
@Bean
public PlayTimes playTimes(){
return new PlayTimes();
}
}
4.切面类
@Pointcut("execution(* com.qhf.aop.example04.BlankCD.play(int)) && args(i)")
public void pointcut(int i){}
参数是int,故play(int)接受一个int 类型参数,&& args(i) 中指定参数名
package com.qhf.aop.example04;
import org.aspectj.lang.annotation.*;
import java.util.HashMap;
import java.util.Map;
@Aspect
public class PlayTimes {
private Map<Integer, Integer> map = new HashMap<>();
@Pointcut("execution(* com.qhf.aop.example04.BlankCD.play(int)) && args(i)")
public void pointcut(int i){
}
/**
* 这首歌播放次数
* @param i
*/
@AfterReturning("pointcut(i)")
public void playTimes(int i){
int count = getPlayCount(i) + 1;
map.put(i, count);
System.out.println("播放次数:" + count);
}
private int getPlayCount(int i){
return map.containsKey(i)? map.get(i): 0;
}
@AfterThrowing("pointcut(i)")
public void noSong(int i){
System.out.println("没有这首歌哟...");
}
}
5.测试
package com.qhf.aop.example04;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AopConfig.class)
public class Test {
@Autowired
private CD avrilCD;
@org.junit.Test
public void test(){
//只有6首歌,0号也有一首歌
avrilCD.play(1);
avrilCD.play(0);
avrilCD.play(1);
avrilCD.play(2);
avrilCD.play(3);
avrilCD.play(4);
avrilCD.play(3);
avrilCD.play(5);
try {
avrilCD.play(6);//没有这首歌,暂时不知用什么方法
} catch (Throwable e){
}
avrilCD.play(1);
}
}
6.运行结果
Playing 'one' by avril; 播放次数:1
Playing 'Head above water' by avril; 播放次数:1
Playing 'one' by avril; 播放次数:2
Playing 'two' by avril; 播放次数:1
Playing 'three' by avril; 播放次数:1
Playing 'four' by avril; 播放次数:1
Playing 'three' by avril; 播放次数:2
Playing 'five' by avril; 播放次数:1
抛异常; 没有这首歌哟...
Playing 'one' by avril; 播放次数:3
二、xml配置实现
1.除了测试类和配置类,其他类全部除去注解
2.配置类
package com.qhf.aop.example05;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource("classpath:aop/example05/aop.xml")
public class AopConfig {
}
3.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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 启动切面代理 -->
<aop:aspectj-autoproxy/>
<!-- 自动装配bean -->
<bean id="playTimes" class="com.qhf.aop.example05.PlayTimes"/>
<bean id="blankCD" class="com.qhf.aop.example05.BlankCD">
<property name="title" value="Head above water"></property>
<property name="artist" value="avril"></property>
<property name="list">
<list>
<value>Head above water</value>
<value>one</value>
<value>two</value>
<value>three</value>
<value>four</value>
<value>five</value>
</list>
</property>
</bean>
<!-- 声明切面 -->
<aop:config>
<aop:aspect ref="playTimes">
<aop:pointcut id="point" expression="execution(* com.qhf.aop.example05.BlankCD.play(int)) and args(i)"/>
<aop:after-returning method="playTimes" pointcut-ref="point"/>
<aop:after-throwing method="noSong" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
4.测试结果相同