Spring之AOP的实现

本文介绍了Spring AOP的两种实现方式,包括不使用注解的XML配置方式和使用注解的方式。详细讲解了配置文件的设置,如切点、通知、切面的定义,并提供了测试及结果分析。
摘要由CSDN通过智能技术生成

基于 XML 方式实现

使用 xml 配置文件(不使用注解)

Maven 依赖

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.0.10.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.8.9</version>
</dependency>

目标接口

public interface IUserManagerService {

    // 查找用户
    public String findUser();
    
    // 添加用户
    public void addUser();
}

目标实现类

public class UserManagerServiceImpl implements IUserManagerService{
    
	private String name;
    
    public void setName(String name){
        this.name=name;
    }
    
    public String getName(){
        return this.name;
    }
    
    public String findUser(){
        System.out.println("============执行业务方法findUser,查找的用户是:"+name+"=============");
        return name;
    }
    
    public void addUser(){
        System.out.println("============执行业务方法addUser=============");
        //throw new RuntimeException();
    }
}

通知切面类

public class AopAspect {
    
    /**
     * 前置通知:目标方法调用之前执行的代码
     */
    public void doBefore(JoinPoint jp){
        System.out.println("===========执行前置通知============");
    }
    
    /**
     * 最终通知:目标方法调用之后执行的代码(无论目标方法是否出现异常均执行)
     * 因为方法可能会出现异常,所以不能获取方法的返回值
     */
    public void doAfter(JoinPoint jp){
        System.out.println("===========执行最终通知============");
    }
    
    /**
     * 后置通知:目标方法正常结束后执行的代码
     * 后置通知是可以获取到目标方法的返回值的
     */
    public void doAfterReturning(JoinPoint jp,String result){
        System.out.println("===========执行后置返回通知============");
        System.out.println("返回值result==================="+result);
    }
    
    /**
     * 异常通知:目标方法抛出异常时执行的代码
     * 可以访问到异常对象
     */
    public void doAfterThrowing(JoinPoint jp,Exception ex){
        System.out.println("===========执行异常通知============");
    }
    
    /**
     * 环绕通知:目标方法调用前后执行的代码,可以在方法调用前后完成自定义的行为。
     * 包围一个连接点(join point)的通知。它会在切入点方法执行前执行同时方法结束也会执行对应的部分。
     * 主要是调用proceed()方法来执行切入点方法,来作为环绕通知前后方法的分水岭。
     * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
     * 而且环绕通知必须有返回值,返回值即为目标方法的返回值
     */
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("======执行环绕通知开始=========");
         // 调用方法的参数
        Object[] args = pjp.getArgs();
        // 调用的方法名
        String method = pjp.getSignature().getName();
        // 获取目标对象
        Object target = pjp.getTarget();
        // 执行完方法的返回值
        // 调用proceed()方法,就会触发切入点方法执行
        Object result=pjp.proceed();
        System.out.println("输出,方法名:" + method + ";目标对象:" + target + ";返回值:" + result);
        System.out.println("======执行环绕通知结束=========");
        return result;
    }
}

spring 的配置文件

<bean id="userManager" class="com.spring.service.impl.UserManagerServiceImpl">
	<property name="name" value="lixiaoxi"></property>
</bean>  
    
<!-- 通知类 -->
<bean id="aspectBean" class="com.spring.aop.AopAspect" />
 
<aop:config>
	<aop:aspect ref="aspectBean">
		<!-- 配置切点 -->
    	<aop:pointcut id="pointcut" expression="execution(* com.spring.service.impl.UserManagerServiceImpl..*(..))"/>
        
    	<!-- 前置通知 -->
		<aop:before method="doBefore" pointcut-ref="pointcut"/>
		<!-- 后置返回通知 --> 
    	<aop:after-returning method="doAfterReturning" pointcut-ref="pointcut" returning="result"/>
    	<!-- 后置通知 -->
    	<aop:after method="doAfter" pointcut-ref="pointcut" />
    	<!-- 环绕通知 -->
    	<aop:around method="doAround" pointcut-ref="pointcut"/>
    	<!-- 异常通知 --> 
    	<aop:after-throwing method="doAfterThrowing" pointcut-ref="pointcut" throwing="ex"/>
    </aop:aspect>
</aop:config>
  • <aop:pointcut> 如果位于 <aop:aspect>元素中,则命名切点只能被当前 <aop:aspect> 内定义的元素访问到,为了能被整个<aop:config>元素中定义的所有增强访问,则必须在<aop:config>下定义切点
  • 如果在<aop:config>元素下直接定义<aop:pointcut>,必须保证<aop:pointcut><aop:aspect>之前定义。<aop:config>下还可以定义<aop:advisor>,三者在<aop:config> 中的配置有先后顺序的要求:首先必须是<aop:pointcut>,然后是<aop:advisor>,最后是<aop:aspect>。而在<aop:aspect>中定义的<aop:pointcut>则没有先后顺序的要求,可以在任何位置定义
  • <aop:pointcut>:用来定义切入点,该切入点可以重用;<aop:advisor> 用来定义只有一个通知和一个切入点的切面;<aop:aspect>:用来定义切面,该切面可以包含多个切入点和通知,而且标签内部的通知和切入点定义是无序的;和 advisor 的区别就在此,advisor只包含一个通知和一个切入点

测试

public class TestAop {
 
    public static void main(String[] args) throws Exception{
        
         ApplicationContext act =  new ClassPathXmlApplicationContext("applicationContext3.xml");
         IUserManagerService userManager = (IUserManagerService)act.getBean("userManager");
         userManager.findUser();
         System.out.println("\n");
         userManager.addUser();
    }
}

测试结果

在这里插入图片描述

使用注解的方式

采用注解来做 aop,主要是将写在 spring 配置文件中的连接点写到注解里面
业务接口和业务实现与上边一样,具体切面类如下

@Aspect
public class AopAspectJ {

	/**
	 * 切点表达式
	 */
	@Pointcut("execution(* com.spring.service.impl.UserManagerServiceImpl..*(..))")
    public void myPointcut() {
    
    }    

    /**
     * 前置通知:即方法执行前拦截到的方法
     * 在目标方法执行之前的通知
     */
    @Before("myPointcut()")
    public void doBefore(JoinPoint jp){
        System.out.println("=========执行前置通知==========");
    }
    
    /**
     * 最终通知:目标方法调用之后执行的通知(无论目标方法是否出现异常均执行)
     * 因为方法可能会出现异常,所以不能获取方法的返回值
     */
    @After(value="myPointcut()")
    public void doAfter(JoinPoint jp){
        System.out.println("===========执行最终通知============");
    }
    
    /**
     * 后置通知:在方法正常执行通过之后执行的通知叫做返回通知
     * 可以获取到目标方法的返回值 
     */
    @AfterReturning(value="myPointcut()",returning="result")
    public void doAfterReturning(JoinPoint jp,String result){
        System.out.println("===========执行后置通知============");
    }
    
    /**
     * 环绕通知:目标方法调用前后执行的通知,可以在方法调用前后完成自定义的行为。
     */
    @Around("myPointcut()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
 
        System.out.println("======执行环绕通知开始=========");
        // 调用方法的参数
        Object[] args = pjp.getArgs();
        // 调用的方法名
        String method = pjp.getSignature().getName();
        // 获取目标对象
        Object target = pjp.getTarget();
        // 执行完方法的返回值
        // 调用proceed()方法,就会触发切入点方法执行
        Object result=pjp.proceed();
        System.out.println("输出,方法名:" + method + ";目标对象:" + target + ";返回值:" + result);
        System.out.println("======执行环绕通知结束=========");
        return result;
    }
    
    /**
     * 异常通知:在目标方法非正常执行完成, 抛出异常的时候会走此方法
     */
    @AfterThrowing(value="myPointcut()",throwing="ex")
    public void doAfterThrowing(JoinPoint jp,Exception ex) {
        System.out.println("===========执行异常通知============");
    }
}

spring 的配置文件

<!-- spring 对 @AspectJ 的支持 -->
<aop:aspectj-autoproxy/>    
    
<!-- 业务类 -->
<bean id="userManager" class="com.spring.service.impl.UserManagerServiceImpl">
	<property name="name" value="lixiaoxi"></property>
</bean>   
    
<!-- 通知类 -->
<bean id="aspectBean" class="com.spring.aop.AopAspectJ" />

springboot 实现 AOP

Maven 依赖

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

通知类

@Component
@Aspect
public class Demo16 {

    // 前置通知:在目标方法执行之前的通知
    @Before("execution (* com.zsg.demo..*.*(..))")
    public void beforeMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().toString();
        Object result = Arrays.asList(joinPoint.getArgs());
        System.out.println("The method name:" + methodName + "--value:" + result);
    }
 
    // 最终通知:目标方法调用之后执行的通知(无论目标方法是否出现异常均执行)
    // 因为方法可能会出现异常,所以不能获取方法的返回值
    @After("execution (* com.xxx.demo..*.*(..))")
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method name:" + methodName + " ends");
    }
 
    // 后置通知:在方法正常执行通过之后执行的通知叫做返回通知,可以获取到目标方法的返回值
    @AfterReturning(value = "execution (* com.xxx.demo..*.*(..))", returning = "result")
    public void afterReturningMethod(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method name:" + methodName + " ends and result=" + result);
    }
 
    // @AfterThrowing: 异常通知
    @AfterThrowing(value = "execution (* com.xxx.demo..*.*(..))", throwing = "e")
    public void afterReturningMethod(JoinPoint joinPoint, Exception e) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method name:" + methodName + " ends and result=" + e);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值