笔记——Spring AOP

概念

AOP是一种思想,而Spring AOP是对这种思想的具体实现,他只是将jdk动态代理和cglib代理整合到一块
简单来说:将程序中重复的代码抽取出来,在程序执行的时候,利用动态代理技术,在不修改源码的基础上,对现有的功能进行增强。

实现方式

JDK动态代理+cglib代理

术语

  • Joinpoint(连接点)
    目标对象中有可能被增强的方法(final修饰的方法可以被jdk动态代理)
  • Pointcut(切入点)
    目标对象中已经被增强的方法
  • Advice(通知/增强)
    增强的代码,一般分为:前置通知before、后置通知after-returning、最终通知after、异常通知after-throwing、环绕通知around
  • Target(目标)
    被代理的对象(切入点/连接点所在的类)
  • Weaving(织入)
    将通知应用到切入点的过程(会产生一个代理对象)
  • Proxy(代理)
    将通知植入到目标对象后形成的代理对象
  • Aspect(切面)
    切入点+通知

代码实现

准备

  • 目标对象(接口和实现类)

    package com.spring.test04;
    
    public interface IStudentService {
    	void saveStudent();
    	void updateStudent();
    	void deleteStudent();
    }
    
    package com.spring.test04;
    
    public class StudentServiceImpl implements IStudentService{
        public void saveStudent() {
            System.out.println("新增学生");
        }
    
        public void updateStudent() {
            System.out.println("更新学生");
        }
    
        public void deleteStudent() {
            System.out.println("删除学生");
        }
    }
    
  • 切面类

    package com.spring.test04.aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    
    public class StudentAspect {
        public void beforeAspect(){
            System.out.println("前置通知");
        }
    
        public void afterReturningAspect() {
            System.out.println("后置通知");
        }
    
        public void afterAspect(){
            System.out.println("最终通知");
        }
    
        public void afterThrowingAspect() {
            System.out.println("异常通知");
        }
    
        public void aroundAspect(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("环绕通知---前");
            Object[] args = joinPoint.getArgs();
            joinPoint.proceed(args);
            System.out.println("环绕通知---后");
        }
    }
    

基于xml

创建配置文件spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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">
    <!-- 目标对象 -->
    <bean id="stu" class="com.spring.test04.StudentServiceImpl"/>
    <!-- 切面 -->
    <bean id="stuAspect" class="com.spring.test04.aspect.StudentAspect"/>
    
    <aop:config>
    	<!-- 切入点  expression切入点表达式 -->
        <aop:pointcut id="pt1" expression="execution(* com.spring.test04..*.*(..))"/>
        <!-- 配置切面 -->
        <aop:aspect id="aspect" ref="stuAspect">
            <aop:before method="beforeAspect" pointcut-ref="pt1"/>
            <aop:after-returning method="afterReturningAspect" pointcut-ref="pt1"/>
            <aop:after method="afterAspect" pointcut-ref="pt1"/>
            <aop:after-throwing method="afterThrowingAspect" pointcut-ref="pt1"/>
            <aop:around method="aroundAspect" pointcut-ref="pt1"/>
        </aop:aspect>
    </aop:config>
</beans>

测试

    public void test03() {
        ApplicationContext app = new ClassPathXmlApplicationContext("spring.xml");
        IStudentService
                stu = (IStudentService) app.getBean("stu");
        stu.saveStudent();

        System.out.println("-----------------");
        stu.deleteStudent();
    }

基于注解

  • 接口不变,目标类(实现类对象)加注解@Service
  • 切面类
    package com.spring.test04.annotation;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    @Component
    @Aspect
    public class StudentAspectAnno {
    
    	//声明执行切入点,方便后续的使用,减少代码量
        @Pointcut("execution(* com.spring.test04..*.*(..))")
        public void pointCut() {}
    
        @Before("execution(* com.spring.test04..*.*(..))")
        public void beforeAspect(){
            System.out.println("前置通知");
        }
    
        @AfterReturning("pointCut()")
        public void afterReturningAspect() {
            System.out.println("后置通知");
        }
    
        @After("pointCut()")
        public void afterAspect(){
            System.out.println("最终通知");
        }
    
        @AfterThrowing("pointCut()")
        public void afterThrowingAspect() {
            System.out.println("异常通知");
        }
    
        @Around("pointCut()")
        public void aroundAspect(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("环绕通知---前");
            Object[] args = joinPoint.getArgs();
            joinPoint.proceed(args);
            System.out.println("环绕通知---后");
        }
    }
    
  • 增加配置类
    package com.spring.test04.annotation;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    @Configuration
    @ComponentScan("com.spring.test04")
    @EnableAspectJAutoProxy
    public class AspectConfig {
    }
    

    如果配置类中没有加注解@EnableAspectJAutoProxy,则需要在配置文件中加上<aop:aspectj-autoproxy />

测试

public void test04() {
	AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(AspectConfig.class);
	IStudentService stu = (IStudentService) app.getBean("studentServiceImpl");
    stu.saveStudent();
}

切入点表达式

切入点指示符

用来指示切入点表达式
SpringAOP支持的AspectJ切入点指示符有:

  • execution:用于匹配符合的方法
  • within:用于匹配指定的类及其子类中的所有方法
  • @Annotation:用于匹配持有指定注解的方法

类型匹配语法

* :匹配任何数量字符
.. :匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数
+ :匹配指定类型的子类型,仅能作为后缀放在类型模式后

切入点使用语法

  • execution
    语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数) 异常类型)
    修饰符、异常类型可省略
    返回值类型可用*表示任意返回值

  • within
    语法:within(包名.类名)

  • @annotation
    语法:@annotation(注解全限定类名)

这篇文章切入点表达式来自 spring aop切入点表达式详解 这里只取了其中一部分内容,感兴趣可点击链接了解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值