1. 程式人生 > 實用技巧 >Spring學習-AOP

Spring學習-AOP

Spring學習-AOP

AOP

注意:需要在pom.xml中匯入包:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

方式一:基於XML檔案實現AOP(不定義切面)

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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
         
        <!--託管bean-->
        <bean id="target" class="com.example.demo.aop.TargetDemo"/>
        <bean id="log" class="com.example.demo.aop.Log"/>
        <bean id="security" class="com.example.demo.aop.Security"/>
            
        <!--定義AOP-->
        <aop:config> <!--AOP配置-->
            <!--定義切點,表示被切入的物件和方法-->
            <aop:pointcut id="pointcut" expression="execution(* com.example.demo.aop.TargetDemo.*(..))"/> 
            <!--在切點上定義一個前置通知-->
            <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
            <!--在切點上定義一個後置通知-->
            <aop:advisor advice-ref="security" pointcut-ref="pointcut"/>
        </aop:config>
</beans>

Java類:

// 切點類:表示該類方法被呼叫時,會先、後呼叫前置、後置通知
public class TargetDemo implements ITarget{

    public void doMyThings()
    {
        System.out.println("target object is running");
    }

}

// 通知類:方法執行前通知
public class Log implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("日誌應該先被執行");
    }
}

// 通知類:方法返回後進行通知
public class Security implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("安全應該在目標物件後執行");
    }
}

// 測試類
public class MyTest {
    @Test
    public void test()
    {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
        ITarget bean = context.getBean("target", ITarget.class);
        bean.doMyThings(); // 方法被呼叫時,會先後呼叫對應的通知方法
    }
}

方式二(自定義切面)

切面:一個類,設定一些前置通知,後置通知等方法,切入到切點中。

XML檔案:

<!--切面類,其中的方法可以切入到切點中-->
<bean id="aop" class="com.example.demo.test.AOP"/>

<aop:config>
    <aop:aspect ref="aop"><!--定義一個切面,為一個類,其中的方法可以切入到切點中-->
        <!--定義切點,在執行方法時,會被切面中定義的方法所切入-->
        <aop:pointcut id="pointcut" expression="execution(* com.example.demo.test.TargetDemo.*(..))"/>
        <!--定義一個前置通知,執行的方法是切面中的beforeMethod()方法-->
        <aop:before pointcut-ref="pointcut" method="beforeMethod"/>
         <!--定義一個後置通知,執行的方法是切面中的afterMethod()方法-->
        <aop:after pointcut-ref="pointcut" method="afterMethod"/>
    </aop:aspect>
</aop:config>

Java類:

// 切面類
public class AOP{
      public void beforeMethod(){
            System.out.println("前置通知被執行");
      }

      public void afterMethod(){
            System.out.println("後置通知被執行");
      }
}

方式三(基於註解)

// 切面類,定義前置,後置,環繞通過方法
@Aspect
public class AOP {

    @Before("execution(* TargetDemo.doMyThings(..))")
    public void before()
    {
        System.out.println("應該在之前被執行");
    }

    @After("execution(* TargetDemo.doMyThings(..))")
    public void after()
    {
        System.out.println("應該在之後被執行");
    }

    @Around("execution(* TargetDemo.doMyThings(..))")
    public void round(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("環繞前通知");
        jp.proceed();
        System.out.println("環繞後執行");
    }
}

XML檔案:開啟自動aop代理

<aop:aspectj-autoproxy/>