Spring中使用AOP的幾種方式

在Spring中使用AOP進行切面編程主要有以下幾種方式:

  1. XML配置
  2. XML+註解
  3. 純註解

XML配置

新建實體類XmlAopBean及切片類XmlAopService

實體類XmlAopBean

package XmlAopBean;

import java.text.MessageFormat;

public class XmlAopBean {

    public void runWithoutArgs() {
        System.out.println("這是無參方法。");
    }

    public void runWithArgs(Integer arg) {
        Integer i=1/arg;
        System.out.println(MessageFormat.format("這是有參方法,參數:{0}", arg));
    }
}


AOP類XmlAopService

package XmlAopBean;

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

import java.text.MessageFormat;

public class XmlAopService {

    public void doBefore(JoinPoint joinPoint) {
        System.out.println(MessageFormat.format("前置通知參數:{0}", joinPoint.getArgs()));
    }

    public void doAfter(JoinPoint joinPoint) {
        System.out.println(MessageFormat.format("後置通知方法:{0}", joinPoint.getSignature()));
    }

    public void doEnd(JoinPoint joinPoint) {
        System.out.println(MessageFormat.format("最終通知目標類:{0}", joinPoint.getTarget()));
    }

    public void doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println(MessageFormat.format("前環繞通知代碼位置:{0}", proceedingJoinPoint.getSourceLocation()));
        proceedingJoinPoint.proceed();
        System.out.println(MessageFormat.format("後環繞通知執行類型:{0}", proceedingJoinPoint.getKind()));
    }
    
    public void doAfterThrow(JoinPoint joinPoint){
        System.out.println(MessageFormat.format("異常通知{0}", joinPoint.getThis()));
    }
}

JoinPoint :獲取切入點方法的相關信息

ProceedingJoinPoint :環繞通知內切入點方法佔位

xmlAopBean.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns="http://www.springframework.org/schema/beans"
       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-4.0.xsd"
>

    <bean class="XmlAopBean.XmlAopBean" id="xmlAopBean"/>
    <bean class="XmlAopBean.XmlAopService" id="xmlAopService"/>

    <aop:config>
        <aop:pointcut id="xmlAopPointCut" expression="execution(void XmlAopBean.XmlAopBean.*(..))"/>

        <aop:aspect ref="xmlAopService">
            <aop:before method="doBefore" pointcut-ref="xmlAopPointCut"/>
            <aop:after method="doAfter" pointcut-ref="xmlAopPointCut"/>
            <aop:after-returning method="doEnd" pointcut-ref="xmlAopPointCut"/>
            <aop:around method="doAround" pointcut-ref="xmlAopPointCut"/>
        </aop:aspect>
    </aop:config>

</beans>

導入依賴

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.14</version>
        </dependency>

引入約束

       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="...
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"

配置AOP

<aop:config>
        <aop:pointcut id="xmlAopPointCut" expression="execution(void XmlAopBean.XmlAopBean.*(..))"/>

        <aop:aspect ref="xmlAopService">
            <aop:before method="doBefore" pointcut-ref="xmlAopPointCut"/>
            <aop:after method="doAfter" pointcut-ref="xmlAopPointCut"/>
            <aop:after-returning method="doEnd" pointcut-ref="xmlAopPointCut"/>
            <aop:around method="doAround" pointcut-ref="xmlAopPointCut"/>
        </aop:aspect>
    </aop:config>

單元測試

import AnnotationAopBean.AnnotationAopBean;
import XmlAopBean.XmlAopBean;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {BaseConfig.class})
public class AOPBeanTest {

    ...

    @Test
    public void xmlAopBeanTest() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("xmlAopBean.xml");

        XmlAopBean xmlAopBean = applicationContext.getBean("xmlAopBean", XmlAopBean.class);

        xmlAopBean.runWithArgs(1);
        xmlAopBean.runWithoutArgs();
    }
}


輸出結果

前置通知參數:1
前環繞通知代碼位置:org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@6d5620ce
這是有參方法,參數:1
後環繞通知執行類型:method-execution
最終通知目標類:XmlAopBean.XmlAopBean@60db1c0e
後置通知方法:void XmlAopBean.XmlAopBean.runWithArgs(Integer)
前置通知參數:{0}
前環繞通知代碼位置:org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@18f8cd79
這是無參方法。
後環繞通知執行類型:method-execution
最終通知目標類:XmlAopBean.XmlAopBean@60db1c0e
後置通知方法:void XmlAopBean.XmlAopBean.runWithoutArgs()


XML+註解

新建實體類XmlAnnotationAopBean和AOP類XmlAnnotationAopService

實體類XmlAnnotationAopBean

package XmlAnnotationAopBean;

import org.springframework.stereotype.Component;

import java.text.MessageFormat;

@Component
public class XmlAnnotationAopBean {

    public void runWithoutArgs() {
        System.out.println("這是無參方法。");
    }

    public void runWithArgs(Integer arg) {
        Integer i = 1 / arg;
        System.out.println(MessageFormat.format("這是有參方法,參數:{0}", arg));
    }
}

AOP類XmlAnnotationAopService

package XmlAnnotationAopBean;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.text.MessageFormat;

@Component
@Aspect
public class XmlAnnotationAopService {

    @Pointcut("execution(void XmlAnnotationAopBean.*(..))")
    public void pointCut() {
    }

    @Before("pointCut()")
    public void doBefore(JoinPoint joinPoint) {
        System.out.println(MessageFormat.format("前置通知參數:{0}", joinPoint.getArgs()));
    }

    @After("pointCut()")
    public void doAfter(JoinPoint joinPoint) {
        System.out.println(MessageFormat.format("後置通知方法:{0}", joinPoint.getSignature()));
    }

    @AfterReturning("pointCut()")
    public void doEnd(JoinPoint joinPoint) {
        System.out.println(MessageFormat.format("最終通知目標類:{0}", joinPoint.getTarget()));
    }

    @Around("pointCut()")
    public void doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println(MessageFormat.format("前環繞通知代碼位置:{0}", proceedingJoinPoint.getSourceLocation()));
        proceedingJoinPoint.proceed();
        System.out.println(MessageFormat.format("後環繞通知執行類型:{0}", proceedingJoinPoint.getKind()));
    }
    
    @AfterThrowing("pointCut()")
    public void doAfterThrow(JoinPoint joinPoint){
        System.out.println(MessageFormat.format("異常通知{0}", joinPoint.getThis()));
    }
}

@Aspect:指定爲切面類

XmlAnnotationAopBean.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
       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-4.0.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"
>

    <context:component-scan base-package="XmlAnnotationAopBean"/>
    <aop:aspectj-autoproxy/>

</beans>

aop:aspectj-autoproxy/:開啓自動AOP代理

單元測試

import XmlAnnotationAopBean.XmlAnnotationAopBean;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:XmlAnnotationAopBean.xml")
public class XmlAnnotationAopBeanTest {
    @Autowired
    private XmlAnnotationAopBean xmlAnnotationAopBean;

    @Test
    public void xmlAnnotationAopBeanTest() {
        xmlAnnotationAopBean.runWithArgs(1);
        xmlAnnotationAopBean.runWithoutArgs();
    }
}

輸出結果

前環繞通知代碼位置:org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@5965d37
前置通知參數:1
這是有參方法,參數:1
後環繞通知執行類型:method-execution
後置通知方法:void XmlAnnotationAopBean.XmlAnnotationAopBean.runWithArgs(Integer)
最終通知目標類:XmlAnnotationAopBean.XmlAnnotationAopBean@38467116
前環繞通知代碼位置:org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@5b7a7f33
前置通知參數:{0}
這是無參方法。
後環繞通知執行類型:method-execution
後置通知方法:void XmlAnnotationAopBean.XmlAnnotationAopBean.runWithoutArgs()
最終通知目標類:XmlAnnotationAopBean.XmlAnnotationAopBean@38467116

純註解

新建配置註解類BaseConfig、實體類AnnotationAopBean和AOP類AnnotationAopService

註解配置BaseConfig

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackages = "AnnotationAopBean")
@EnableAspectJAutoProxy
public class BaseConfig {
}

@EnableAspectJAutoProxy:開啓自動AOP代理

實體類AnnotationAopBean

package AnnotationAopBean;

import org.springframework.stereotype.Component;

import java.text.MessageFormat;

@Component
public class AnnotationAopBean {

    public void runWithoutArgs() {
        System.out.println("這是無參方法。");
    }

    public void runWithArgs(Integer arg) {
        Integer i = 1 / arg;
        System.out.println(MessageFormat.format("這是有參方法,參數:{0}", arg));
    }
}


AOP類AnnotationAopService

package AnnotationAopBean;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.text.MessageFormat;

@Component
@Aspect
public class AnnotationAopService {


    @Pointcut("execution(void AnnotationAopBean.*(..))")
    public void pointCut() {
    }

    @Before("pointCut()")
    public void doBefore(JoinPoint joinPoint) {
        System.out.println(MessageFormat.format("前置通知參數:{0}", joinPoint.getArgs()));
    }

    @After("pointCut()")
    public void doAfter(JoinPoint joinPoint) {
        System.out.println(MessageFormat.format("後置通知方法:{0}", joinPoint.getSignature()));
    }

    @AfterReturning("pointCut()")
    public void doEnd(JoinPoint joinPoint) {
        System.out.println(MessageFormat.format("最終通知目標類:{0}", joinPoint.getTarget()));
    }

    @Around("pointCut()")
    public void doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println(MessageFormat.format("前環繞通知代碼位置:{0}", proceedingJoinPoint.getSourceLocation()));
        proceedingJoinPoint.proceed();
        System.out.println(MessageFormat.format("後環繞通知執行類型:{0}", proceedingJoinPoint.getKind()));
    }
    
    @AfterThrowing("pointCut()")
    public void doAfterThrow(JoinPoint joinPoint){
        System.out.println(MessageFormat.format("異常通知{0}", joinPoint.getThis()));
    }
}

單元測試

import AnnotationAopBean.AnnotationAopBean;
import XmlAopBean.XmlAopBean;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {BaseConfig.class})
public class AOPBeanTest {
    @Autowired
    private AnnotationAopBean annotationAopBean;

    @Test
    public void annotationAopBeanTest() {
        annotationAopBean.runWithArgs(1);
        annotationAopBean.runWithoutArgs();
    }
    
    ....
}

輸出結果

前環繞通知代碼位置:org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@5f9edf14
前置通知參數:1
這是有參方法,參數:1
後環繞通知執行類型:method-execution
後置通知方法:void AnnotationAopBean.AnnotationAopBean.runWithArgs(Integer)
最終通知目標類:AnnotationAopBean.AnnotationAopBean@68746f22
前環繞通知代碼位置:org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@2f01783a
前置通知參數:{0}
這是無參方法。
後環繞通知執行類型:method-execution
後置通知方法:void AnnotationAopBean.AnnotationAopBean.runWithoutArgs()
最終通知目標類:AnnotationAopBean.AnnotationAopBean@68746f22

源碼下載

[email protected]:Angryshark128/Practice.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章