简介
什么是AOP?
spring中如何使用AOP?
AOP简介
aop:面向切面编程,比如说在一个应用系统中,有许多服务接口;假设现在需要在某些功能上加上一些日志,记录用户操作过程。如果在这些接口上都添加一段一样的代码来进行记录,这样虽然可以达到目的,但是实际中肯定是不允许的,因为这个工作量太大,代码也很冗余。怎么解决呢?将这些公共部分的功能提取出来,然后给需要的接口进行配置,那不就好了吗。
可能讲的很抽象,如果还不是很清楚这个概念可以找下度娘
AOP常用术语
通知(Advice)
指的是:装饰的这个方法,其中切面是什么以及何时使用
连接点(Join point)
指的是:在应用执行过程中能够插入切面的一个点
切点(Pointcut)
指的是:应用切面的一个点,主要是定义了切面在何处使用
切面(Aspect)
指的是:装饰的这个类,也就是通知和切点的结合
织入
指的是:将切面应用到这个目标对象的这一过程
AOP表达式
execution(* cn.simfg.note.aop.Performance.perform(..))
第一个参数:方法返回类型,*表示接匹配任何返回参数
第二个参数(斜体):方法的全类路径
第三个参数:方法名
第四个参数:方法参数,..表示匹配任意个方法参数
定义切面
package cn.simfg.note.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import java.util.Date;
/**
* @Author: simfg
* @Description: 切面
* @Date: 2017/10/5
*/
@Aspect
public class Audience {
//这个方法体中没有任何内容,主要是这个注解的标示
@Pointcut("execution(* cn.simfg.note.aop.Performance.perform(..))")
public void performance() {
}
// 一般写法,如果类中有许多切面表达式都是这样,那么可以使用Pointcut标签
@Before("execution(* cn.simfg.note.aop.Performance.perform(..))")
public void silenceCellPhone() {
System.out.println("Silencing cell phones ...");
}
@Before("performance()")
public void takeSeats() {
System.out.println("take seats");
}
@AfterReturning("performance()")
public void applause() {
System.out.println("CLAP,CLAP,CLAP ...");
}
@AfterThrowing("performance()")
public void fault() {
System.out.println("Error ...");
}
@Around("performance()")
public void timer(ProceedingJoinPoint jp) throws Throwable {
Date date = new Date();
jp.proceed();
Date date1 = new Date();
System.out.println(date1.getTime() - date.getTime());
}
}
涉及注解:
@Aspect,表示这个类是一个切面
@Before,前置通知,通知在目标对象的方法被调用之前
@After,后置通知,通知在目标对象的方法完成之后
@AfterReturning,在After之后
@AfterThrowing,在After之后,如果目标对象的方法抛出异常则调用
@Around,环绕通知,通知方法将目标对象的方法封装起来
@Pointcut,如果通知中的值都是一样,可以使用标签来减少冗余
配置切面及其测试
被装饰对象
public class Performance {
public void perform() {
System.out.println("perform ...");
}
public void music(String name) {
System.out.println("sing " + name + " ...");
}
}
javaConfig
@Configuration
@ComponentScan(basePackages = {"cn.simfg.note.aop"})
@EnableAspectJAutoProxy
public class AopConfig {
@Bean
public Performance performance(){
return new Performance();
}
@Bean
public Audience audience(){
return new Audience();
}
}
注解:@EnableAspectJAutoProxy,启用切面
注意: 需要将两个类,即切面对象及其需要被装饰的对象
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {cn.simfg.note.config.AopConfig.class})
public class AopTest {
@Autowired
private Performance performance;
@Test
public void testPerformance(){
performance.perform();
}
}
切面接受参数
Audience.java添加一个这样的方法
@Before("execution(* cn.simfg.note.aop.Performance.music(..)) && args(name)")
public void readyMusic(String name) {
System.out.println("It's ready for " + name);
}
主要就是在表达式中添加一个args(name),name表示目标对象方法的参数名称,注意不要遗漏了&&符号
在之前已经在Performance这个类中添加了music这个方法
AopTest.java添加测试方法:
@Test
public void testMusic(){
performance.music("换世绝恋");
}
xml配置切面
1.切面对象还是像之前一样,但是将方法上的注解去掉
2.xml中配置通知
<!-- 开启aop -->
<aop:aspectj-autoproxy/>
<bean id="audience" class="cn.simfg.note.aop.Audience"/>
<!-- aop配置 -->
<aop:config>
<aop:aspect ref="audience">
<aop:pointcut id="performance" expression="execution(* cn.simfg.note.aop.Performance.perform(..))"/>
<aop:before method="silenceCellPhone" pointcut-ref="performance"/>
</aop:aspect>
</aop:config>
测试方法就和之前的一样了,如果你在这个过程中遇到什么问题可以进行留言
扫描左侧二维码,关注个人公众号,让我们一起探索世界吧