AOP 是软件设计领域中的面向切面编程,它是面向对象编程的一种补充和完善
AOP目的:基于OCP(开闭原则)在不改变原有系统核心业务代码的基础上动态添加一些扩展功能并可以控制对象的执行。
应用场景示例:AOP常应用于日志的处理,事务处理,权限处理,缓存处理等
AOP底层基于代理机制实现:
org.springframework
spring-context
4.3.9.RELEASE
org.aspectj
aspectjrt
1.8.9
org.aspectj
aspectjweaver
1.8.9
public interface HelloService {
void sayHello(String msg);
}
public class HelloServiceImpl implements HelloService {
public void sayHello(String msg) {
//假设这条语句是我们系统中的核心业务
System.out.println(msg);
}
}
public class LoggingAspect {
public void beforeMethod(){
System.out.println("method start");
}
public void afterMethod(){
System.out.println("method end");
}
}
public class TestAOP01 {
private ClassPathXmlApplicationContext ctx;
@Before
public void init(){
ctx=new ClassPathXmlApplicationContext("spring-configs.xml");
}
@Test
public void testSayHello(){
HelloService helloService=
ctx.getBean("helloService",HelloService.class);
helloService.sayHello("cgb1712");
}
@After
public void destory(){
ctx.close();
}
}
public interface OrderService {
public void saveOrder();
public void deleteOrder();
}
@Aspect
@Service
public class TimeAspect {
@Pointcut("bean(orderService)")
public void pointcut(){}
/**增强功能:前置通知(业务方法执行之前执行)*/
@Before("pointcut()")
public void begin(){
System.out.println("start:"+System.nanoTime());
}
/**增强功能:最终通知(业务方法执行最后执行,
*无论业务方法是否执行成功,此功能都要执行)*/
@After("pointcut()")
public void end(){
System.out.println("end:"+System.nanoTime());
}
}
@ComponentScan("com.spring.beans")
@EnableAspectJAutoProxy
public class AppConfig {
}
public class TestAOP01 {
public static void main(String[] args) {
//1.初始化容器
ClassPathXmlApplicationContext ctx=
new ClassPathXmlApplicationContext(
"applicationContext.xml");
//2.获取bean对象
OrderService os=(OrderService)
ctx.getBean("orderService",
OrderService.class);
//3.执行业务方法
os.saveOrder();
os.deleteOrder();
//4.释放资源
ctx.close();
}
}
public class TestAOP02 {
public static void main(String[] args) {
//1.初始化容器对象
AnnotationConfigApplicationContext ctx=
new AnnotationConfigApplicationContext(
AppConfig.class);
//2.获取Bean对象
OrderService orderService=
ctx.getBean("orderService", OrderService.class);
//3.执行业务
orderService.saveOrder();
//orderService.deleteOrder();
//4.释放资源
ctx.close();
}
}
指示符 | 作用 |
bean | 匹配指定bean id的方法执行 |
within | 指定包下类型内的方法执行 |
@annotation | 指定注解修饰的方法执行 |
execution | 细粒度方法匹配执行具体业务 |
bean("userServiceImpl")) |
指定一个类 |
bean("*ServiceImpl") |
指定所有的后缀为service的类 |
within("aop.service.UserServiceImpl") |
指定类,只能指定一个类 |
within("aop.service.*") |
只包括当前目录下的类 |
within("aop.service..*") |
指定当前目录包含所有子目录中的类 |
语法:execution(返回值类型 包名.类名.方法名(参数列表))
execution(void aop.service.UserServiceImpl.addUser()) |
匹配方法 |
execution(void aop.service.PersonServiceImpl.addUser(String)) |
方法参数必须为字符串 |
execution(* aop.service..*.*(..)) |
万能配置 |
@annotation("com.jt.common.anno.RequestLog")) |
指定一个需要实现增强功能的方法 |
A.try{ @Before核心业务 @AfterReturning }catch(Exception e){ ... @AfterThrowing }finally{ @After }
B.以上四个一起使用时可以直接用@Around通知替换
A.切入点及前置通知,后置通知,返回通知,异常通知,环绕通知的配置
B.切入点及环绕通知的配置
A.切入点及前置通知,后置通知,返回通知,异常通知,环绕通知的配置
@Aspect
@Service
public class LogAspect {
@Pointcut("bean(orderServiceImpl)")
public void doLog(){}
@Before("doLog()")
public void doBefore(){
System.out.println("log before");
}
@After("doLog()")
public void doAfter(){
System.out.println("log after");
}
/**核心业务正常结束时执行
* 说明:假如有after,先执行after,再执行returning*/
@AfterReturning("doLog()")
public void doAfterReturning(){
System.out.println("log doAfterReturning");
}
/**核心业务出现异常时执行
说明:假如有after,先执行after,再执行Throwing*/
@AfterThrowing("doLog()")
public void doAfterThrowing(){
System.out.println("log doAfterThrowing");
}
}
B.切入点及环绕通知
@Component
@Aspect
public class TxManager {
@Pointcut("execution(com.company.spring.service..*.*(..))")
public void pointCut() {}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint)
throws Throwable{
try{
System.out.println("事务开始");
Object result = joinPoint.proceed();//执行目标方法
System.out.println("提交事务");
return result;
}catch(Exception e){
System.out.println("回滚事务");
throw e;
}finally{
System.out.println("释放资源");
}
}
}
实际项目中可能会有多个切面,切面之间的执行可能需要一定的顺序。
A.xml方式配置执行顺序
B.注解方式配置执行顺序:借助@Order注解
@Order(1)
@Aspect
@Component
public class TxManager {
@Pointcut("execution(* com.company.spring.service..*.(..))")
public void pointCut() {}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint)
throws Throwable{
System.out.println("事务开始");
Object result = joinPoint.proceed();
System.out.println("事务结束");
return result;
}
}
@Order(2)
@Aspect
@Component
public class LoggingAspect {
@Pointcut("execution(* com.company.spring.service..*.(..))")
public void pointCut() {}
@Before("pointCut()")
public void beforeMethod() {
System.out.println("beforeMethod");
}
@After("pointCut()")
public void afterMethod() {
System.out.println("afterMethod");
}
}