1. 什么是AOP
AOP是Aspect Oriented Progamming(面向切面编程)的简称,和OOP(面向对象编程)一样是一种编程思想,是对OOP的一种补充。
AOP旨在将横切关注点从业务主体逻辑中进行剥离,实现关注点分离,以提高程序的模块化程度。即业务模块只需要关注业务逻辑,无需关注日志、安全、事务等通用逻辑。
2. AOP相关术语
切面(Aspect):一个关注点的模块化(比如日志、事务、权限验证等)。以注解@Aspect的形式放在类上方,声明一个切面。
连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候,都可以是连接点。一般都是在方法调用的时候,如execution(* com.demo.UserService.insertUser(..)).
切点(Pointcut):定义了在筛选出的连接点上执行通知。
通知: 通知增强。需要完成的工作叫做通知。比如定义好事务、日志等业务逻辑,然后在需要的地方使用。增强包括以下五个方面:
1)@Before: 在目标方法执行之前执行
2)@After:在目标方法执行之后执行(方法执行成功或失败都会调用)
3)@AfterReturning:在目标方法成功执行之后执行
4)@AfterThrowing:在目标方法抛出异常之后执行
5)@Around:在被通知方法调用之前和调用之后执行
切面: 切点和通知的结合。通知和切点定义的切面的全部功能:是什么,在何时何处完成其功能。
引入:允许向现有的类添加新方法或属性。
织入:把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中,在目标对象的生命周期中有多个地方可以织入(这不同博客写的不一样,之后再补充)。
3. AOP代码实例
切面类
package cn.com.demo.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
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 org.springframework.stereotype.Component;
@Component
@Aspect
public class LogAop {
@Pointcut("execution(* cn.com.demo.service.UserService.insertUser(..))")
public void ponitCut() {
}
@Before("ponitCut()")
public void beforeAdvice() {
System.out.println("beforeAdvice");
}
@After("ponitCut()")
public void afterAdvice() {
System.out.println("afterAdvice");
}
//环绕通知。注意要有ProceedingJoinPoint参数传入
@Around("ponitCut()")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("注解类型环绕通知..环绕前");
pjp.proceed();//执行方法
System.out.println("注解类型环绕通知..环绕后");
}
}
连接点所在服务类
package cn.com.demo.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void insertUser() {
System.out.println("插入用户成功");
}
public boolean updateUser() {
System.out.println("更新用户成功");
return true;
}
}
测试类
package cn.com.demo.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.com.demo.service.UserService;
public class TestAop {
private ClassPathXmlApplicationContext ac;
public TestAop() {
}
@Before
public void before() {
ac = new ClassPathXmlApplicationContext("applicationContext.xml");
}
@Test
public void test() {
try {
UserService userService = (UserService) ac.getBean("userService");
userService.insertUser();
} catch (Exception e) {
e.printStackTrace();
}
}
}
applicationContext.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<bean id="userService" class="cn.com.demo.service.UserService"/>
<!-- 启用注释驱动自动注入 -->
<context:annotation-config/>
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="cn.com.demo"></context:component-scan>
<!-- 开启aop注解方式,此步骤不能少,这样java类中的aop注解才会生效 -->
<aop:aspectj-autoproxy/>
</beans>