SpringAOP切入方式

本文详细介绍了Spring AOP的核心概念,包括AOP与OOP的关系、切面、切点、通知等,并通过接口切入、注解方式和Schema方式展示了不同类型的切入方法,帮助读者深入理解Spring AOP的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AOP与OOP是什么关系?

AOP的实现技术有多种,其中与Java无缝对接的是一种称为AspectJ的技术,Spring AOP 与AspectJ 实现原理上并不完全一致,但功能上是相似的。AOP的出现确实解决外围业务代码与核心业务代码分离的问题,但它并不会替代OOP,如果说OOP的出现是把编码问题进行模块化,那么AOP就是把涉及到众多模块的某一类问题进行统一管理

切面(Aspect)包含了切点(PointCut)、连接点(JoinPoint);额外还有通知(Advice),织入(Weaving),引入(Introduce)。

package springMVCmybatis.com.my.aop;
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Around; 
import org.aspectj.lang.annotation.Before; 
import org.aspectj.lang.annotation.Pointcut; 
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint; 
import org.aspectj.lang.annotation.After; 
import org.aspectj.lang.annotation.AfterReturning; 
import org.aspectj.lang.annotation.AfterThrowing; 
import org.springframework.core.annotation.Order;
@Aspect
// 切面执行顺序
@Order(3)
public class MyAopTest {
      @Pointcut("execution(* springMVCmybatis..addController.addEmp(..))") 
        private void pointCutMethod() { 
        } 
       
      @Pointcut("execution(* springMVCmybatis.com.my.aop.UserServiceImp.*(..))") 
        private void testAOP() { 
        }
      /*
       *  声明前置通知 ,JoinPont是srpring提供的静态变量,
       *  通过joinPoint参数可以获得目标方法的类名,方法参数,方法名等信息,这个参数可有可无。
       */
        
        @Before("pointCutMethod() || testAOP()") 
        public void doBefore(JoinPoint joinPoint) { 
            System.out.println("@Before:开始添加--order=3"); 
        } 
       
        //声明后置通知 ,如果result的类型与proceed执行的方法返回的参数类型不匹配那么就不会执行这个方法
        @AfterReturning(pointcut = "pointCutMethod()  || testAOP()", returning = "result") 
        public void doAfterReturning(String result) { 
            System.out.println("@AfterReturning:后置通知--order=3"); 
            System.out.println("---" + result + "---"); 
        } 
       
        //声明例外通知 
        @AfterThrowing(pointcut = "pointCutMethod() || testAOP()", throwing = "e") 
        public void doAfterThrowing(Exception e) { 
            System.out.println("@AfterThrowing:例外通知--order=3"); 
            System.out.println(e.getMessage()); 
        } 
       
        //声明最终通知 
        @After("pointCutMethod() || testAOP()") 
        public void doAfter() { 
            System.out.println("@After:最终通知--order=3"); 
        } 
      /*
       * 声明环绕通知
       * 参数必须是ProceedingJoinPoint,通过该对象的proceed()方法来执行目标函数,
       * proceed()的返回值就是环绕通知的返回值,proceedingJoinPoint是个接口,
       * implement JoinPoint,所以也可以获得目标函数的类名,方法名等参数。
       */
         
        @Around("pointCutMethod() || testAOP()") 
        public Object doAround(ProceedingJoinPoint pjp) throws Throwable { 
            System.out.println("@Around:进入方法---环绕通知--order=3"); 
            Object o = pjp.proceed(); 
            System.out.println("@Around:退出方法---环绕通知--order=3"); 
            return o; 
        }
 
        
}

上面是我写的一个例子,结合例子我们来看看这些核心的概念:

2.1、切面(Aspect):是一个类,里面定义了通知与切点。

2.2、切点(PointCut):表达式(表达式有很多种,如方法签名表达式,类型签名表达式,还有其他的表达式,)。就是告诉程序要在执行哪些核心业务的时候,执行非核心的业务。

2.3、通知(advice):五种通知方式:

  • @Before:前置通知,在调用目标方法之前执行通知定义的任务
  • @After:后置通知,在目标方法执行结束后,无论执行结果如何都执行通知定义的任务
  • @After-returning:后置通知,在目标方法执行结束后,如果执行成功,则执行通知定义的任务
  • @After-throwing:异常通知,如果目标方法执行过程中抛出异常,则执行通知定义的任务
  • @Around:环绕通知,在目标方法执行前和执行后,都需要执行通知定义的任务。

3.1:方法签名表达式

1

2

execution(<修饰符模式>?<返回类型模式><方法所在类的完全限定名称模式>(<参数模式>)<异常模式>?)

execution(modifiers-pattern? ret-type-pattern fully-qualified-class-name (param-pattern) throws-pattern?)   

其实如果单纯的给定这个表达式还是不容易记忆,下面对比方法的定义来记忆,一个java方法的全部定义方式可以表示成下面的方式:

public String springMVCmybatic.com.my.aop.UserServiceImp(String a, int b) throw Exception{

}

  • modifier-pattern?:表示方法的修饰符,可有可无;对应的就是 public
  • ret-type-pattern:表示方法的返回值;对应的就是 String
  • fully-qualified-class-name  方法所在类的完全限定名称;对应的就是 springMVCmybatic.com.my.aop.UserServiceImp
  • param-pattern:表示方法的参数;对应的就是 String a, int b
  • throws-pattern:表示方法抛出的异常,可有可无;对应的就是 throw Exception

3.2:&&,||,!

1

2

3

4

5

6

7

@Around("pointCutMethod() || testAOP()"

      public Object doAround(ProceedingJoinPoint pjp) throws Throwable { 

          System.out.println("@Around:进入方法---环绕通知"); 

          Object o = pjp.proceed(); 

          System.out.println("@Around:退出方法---环绕通知"); 

          return o; 

      }

表达式之间可以采用与,或,非的方式来过滤。

四:多个切点的执行顺序

 上面的例子中,定义了order=3,重新创建一个切面,定义order=6,执行的结果是:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

@Around:进入方法---环绕通知--order=3

@Before:开始添加--order=3

@Around:进入方法---环绕通知--order=6

@Before:开始添加--order=6

============执行业务方法findUser,查找的用户是:张三=============

@Around:退出方法---环绕通知--order=6

@After:最终通知--order=6

@AfterReturning:后置通知--order=6

---张三---

@Around:退出方法---环绕通知--order=3

@After:最终通知--order=3

@AfterReturning:后置通知--order=3

---张三---

 

 

@Around:进入方法---环绕通知--order=3

@Before:开始添加--order=3

@Around:进入方法---环绕通知--order=6

@Before:开始添加--order=6

============执行业务方法addUser=============

@After:最终通知--order=6

@AfterThrowing:例外通知--order=6

null

@After:最终通知--order=3

@AfterThrowing:例外通知--order=3

null

 从结果中可以看出order越小越先执行,执行完了之后就order越小就越后推出。总结为下面的图:

 

 

                

接口切入方式

实现类(全文通用)

package com.pb.entity;
/**
 * 实体类
 */
public class Hello {
    private String name;
    private String password;
    
    public void show(){
        System.out.println("姓名 :"+this.getName()+"密码: "+this.getPassword());
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    

}

1.1、前置增强

package com.pb.aop;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;
/**
 * 前置增强的Bean
 * @author Administrator
 *实现MethodBeforeAdvice接口
 */
public class BeforeAdded implements MethodBeforeAdvice {

    @Override
    public void before(Method arg0, Object[] arg1, Object arg2)
            throws Throwable {
        System.out.println("====前置增强!=====");

    }

}

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:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<!--hello Bean  -->
<bean id="hello" class="com.pb.entity.Hello" p:name="张三" p:password="123qwe"/>
<!--切入的Bean  -->
<bean id="beforeAdd" class="com.pb.aop.BeforeAdded"/>
<!--前置增强切入的Bean  -->
<aop:config>
<!-- 切入点 -->
<aop:pointcut expression="execution(* com.pb.entity.Hello.*(..))" id="myPoint"/>
<!-- 关联切入类和切入点 -->
<aop:advisor advice-ref="beforeAdd" pointcut-ref="myPoint"/>
</aop:config>
</beans>

1.2、后置增强

package com.pb.aop;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;
/**
 * 后置增强
 */
public class AfterAdded implements AfterReturningAdvice {

    @Override
    public void afterReturning(Object arg0, Method arg1, Object[] arg2,
            Object arg3) throws Throwable {
        System.out.println("====这里是后置增强!====");

    }

}

 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:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<!--hello Bean  -->
<bean id="hello" class="com.pb.entity.Hello" p:name="张三" p:password="123qwe"/>
<!--切入的Bean  -->

<!--后置增强切入的Bean  -->
<bean id="afterAdd" class="com.pb.aop.AfterAdded"/>
<aop:config>
<!-- 切入点 -->
<aop:pointcut expression="execution(* com.pb.entity.Hello.*(..))" id="myPoint"/>
<!-- 关联后置增强切入类和切入点 -->
<aop:advisor advice-ref="afterAdd" pointcut-ref="myPoint"/>
</aop:config>
<!--后置增强切入的Bean  -->

</beans>

1.3、异常增强

实体类中增加异常

package com.pb.entity;
/**
 * 实体类
 */
public class Hello {
    private String name;
    private String password;
    
    public void show(){
        System.out.println("姓名 :"+this.getName()+"密码: "+this.getPassword());
        //加入异常
        System.out.println(1/0);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    

}
package com.pb.aop;

import java.lang.reflect.Method;

import org.springframework.aop.ThrowsAdvice;
/**
 * 异常增强类
 * @author Administrator
 *
 */
public class ThrowingAdded implements ThrowsAdvice {
    //第一种写法
    public void afterThrowing(Exception ex){
        System.out.println("我是异常增强!,,没处理异常,有问题就找我");
        
    }
    //第二种写法
    public void afterThrowing(Method arg0, Object[] arg1, Object arg2,Exception ex){
        System.out.println("我是异常增强!,,没处理异常,有问题就找我");
        
    }

}

 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:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<!--hello Bean  -->
<bean id="hello" class="com.pb.entity.Hello" p:name="张三" p:password="123qwe"/>
<!--切入的Bean  -->

<!--异常增强切入的Bean  -->
<bean id="throwAdd" class="com.pb.aop.ThrowingAdded"/>
<aop:config>
<!-- 切入点 -->
<aop:pointcut expression="execution(* com.pb.entity.Hello.*(..))" id="myPoint"/>
<!-- 关联异常增强切入类和切入点 -->
<aop:advisor advice-ref="throwAdd" pointcut-ref="myPoint"/>
</aop:config>

</beans>

1.4、以上综合

<?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:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<!--hello Bean  -->
<bean id="hello" class="com.pb.entity.Hello" p:name="张三" p:password="123qwe"/>
<!--切入的Bean  -->
<!--前置增强切入的Bean  -->
<bean id="beforeAdd" class="com.pb.aop.BeforeAdded"/>

<!--后置增强切入的Bean  -->
<bean id="afterAdd" class="com.pb.aop.AfterAdded"/>
<!--异常增强切入的Bean  -->
<bean id="throwAdd" class="com.pb.aop.ThrowingAdded"/>
<aop:config>
<!-- 切入点 -->
<aop:pointcut expression="execution(* com.pb.entity.Hello.*(..))" id="myPoint"/>
<!-- 关联前置增强切入类和切入点 -->
<aop:advisor advice-ref="beforeAdd" pointcut-ref="myPoint"/>
<!-- 关联后置增强切入类和切入点 -->
<aop:advisor advice-ref="afterAdd" pointcut-ref="myPoint"/>
<!-- 关联异常增强切入类和切入点 -->
<aop:advisor advice-ref="throwAdd" pointcut-ref="myPoint"/>
</aop:config>

</beans>

1.5、环绕增强

package com.pb.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
 * 环绕增强
 * @author Administrator
 *实现接口MethodIntercepor
 */
public class AroundAdded implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation arg0) throws Throwable {
        Object result=null;
        try {
            System.out.println("环绕增强开始!");
             result=arg0.proceed();
            System.out.println("环绕增强结束!");
        } catch (Exception e) {
            System.out.println("环绕增强异常!");
        }finally{
            System.out.println("环绕增强最终增强!");
        }
        
        return result;
    }

}

 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:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
    <!-- 关联Bean Hello -->
<bean id="hello" class="com.pb.entity.Hello" p:name="张三" p:password="qewr"/>
<!--环绕增强的Bean  -->
<bean id="aroundAdded" class="com.pb.aop.AroundAdded"></bean>

<aop:config>
<!--  切入点-->
<aop:pointcut expression="execution(* com.pb.entity.*.*(..))" id="myPoint"/>
<!--关联切入点  -->
<aop:advisor advice-ref="aroundAdded" pointcut-ref="myPoint"/>
</aop:config>
</beans>

二、注解方式

package com.pb.aop;

import org.aspectj.lang.JoinPoint;
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;

/**
 * 注解的方式现实AOP
 * @author Administrator
 *
 */
@Aspect
public class MyAnnotionAOP {
    
    /*
     * 前置
     */
    @Before(value="execution(* com.pb.entity.*.*(..))")
    public void before(JoinPoint point){
        
        System.out.println("前置增强");
        System.out.println(point.getClass());
    }
    /*
     * 后置
     */
    @AfterReturning(value="execution(* com.pb.entity.*.*(..))")
    public void after(JoinPoint point){
        System.out.println("后置增强");
        //参数个数
        System.out.println(point.getArgs().length);
    }
    /*
     *异常 
     */
    @AfterThrowing(value="execution(* com.pb.entity.*.*(..))")
    public void afterThrowing(JoinPoint point){
        System.out.println("我是异常增强");
        System.out.println(point.getSignature().getName());
    }
    /**
     * 环绕
     */
    @Around(value="execution(* com.pb.entity.*.*(..))")
    public Object myAround(ProceedingJoinPoint point){
        Object result=null;
        
        try {
            System.out.println("环绕增强开始了");
            System.out.println(point.getKind()+point.getArgs());
            point.proceed();
            System.out.println("环绕增强后置增强了");
            System.out.println(point.getTarget()+""+point.getClass());
        } catch (Throwable e) {
            System.out.println("环绕增强,异常增强处理");
            e.printStackTrace();
        }finally{
            System.out.println("环绕增强最终增强");
        }
        
        return result;
        
    }
}

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:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<!-- 关联Bean Hello -->
<bean id="hello" class="com.pb.entity.Hello" p:name="张三" p:password="qewr"/>
<!-- 切入 类 -->
<bean id="myAnnAOP" class="com.pb.aop.MyAnnotionAOP" />
<!--开启自动代理  -->
<aop:aspectj-autoproxy/>

</beans>

三、Schema方式(推荐)

package com.pb.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;


/**
 * SCHEMA方式切入类
 * 
 * @author Administrator
 * 
 */
public class MySchemaAOP {

    /**
     * 前置切入 可以有参数但是固定写法
     */
    public void before(JoinPoint point){
        System.out.println("这里是前置增强切入");
        System.out.println(point.getKind()+point.getArgs().toString());
    }
    /**
     * 后置切入
     */
    public void after(JoinPoint point){
        System.out.println("这里是后置增强切入");
        System.out.println(point.getTarget()+point.getSignature().getName());
    }
    /**
     * 异常切入
     */
    public void myException(JoinPoint point){
        System.out.println("这里是异常增强切入");
        System.out.println(point.getSourceLocation());
    }
    /**
     * 环绕增强切入
     */
    public Object myAround(ProceedingJoinPoint point){
        Object resut=null;
        try {
            System.out.println("环绕增强---前置增强");
            resut=point.proceed();
            System.out.println("环绕增强---后置增强");
        } catch (Throwable e) {
            System.out.println("环绕增强---异常增强");
            e.printStackTrace();
        }finally{
            System.out.println("环绕增强---最终增强");
        }
        return resut;
    }
}

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:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<!-- 关联Bean Hello -->
<bean id="hello" class="com.pb.entity.Hello" p:name="张三" p:password="qewr"/>
<!-- 切入 类 -->
<bean id="mySchemaAOP" class="com.pb.aop.MySchemaAOP"/>

<aop:config>
<!--  切入点-->
<aop:pointcut expression="execution(* com.pb.entity.*.*(..))" id="myPoint"/>
<!--关联切入类、方法和切入点  -->
<aop:aspect ref="mySchemaAOP">
<!-- 切入 前置方法和切入点-->
<aop:before method="before" pointcut-ref="myPoint"/>
<!-- 切入 后置方法和切入点-->
<aop:after method="after" pointcut-ref="myPoint"/>
<!-- 切入 异常方法和切入点-->
<aop:after method="myException" pointcut-ref="myPoint"/>
<!-- 切入 环绕增加方法和切入点-->
<aop:around method="myAround" pointcut-ref="myPoint"/>
</aop:aspect>
</aop:config>
</beans>

参考:https://www.cnblogs.com/liunanjava/p/4411234.html

https://www.cnblogs.com/boywwj/p/7502185.html

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值