Spring面向切面編程AOP(around)實戰

spring aop的環繞通知around功能強大,咱們這裏就不細說,直接上代碼,看着註釋就能明白java

須要的能夠點擊下載源碼git

1.若是使用註解的方式則須要先建立個註解類github

package com.mb.aop;

import java.lang.annotation.*;

/**
 * 經常使用註解說明:
     * 1. RetentionPolicy(保留策略)是一個enum類型,有三個值
         * SOURCE        --  這個Annotation類型的信息只會保留在程序源碼裏,源碼若是通過了編譯後,Annotation的數據就會消失,並不會保留在編譯好的.class文件裏
         * CLASS         --  這個Annotation類型的信息保留在程序源碼中,同時也會保留在編譯好的.class文件裏面,在執行的時候,並不會把這一些信息加載到虛擬 機(JVM)中去.注意一下,當你沒有設定一個Annotation類型的Retention值時,系統默認值是CLASS。
         * RUNTIME       --  在源碼、編譯好的.class文件中保留信息,在執行的時候會把這一些信息加載到JVM中去的。
         *
     * 2.ElementType @Target中的ElementType用來指定Annotation類型能夠用在哪些元素上
         * TYPE(類型)    -- 在Class,Interface,Enum和Annotation類型上
         * FIELD        -- 屬性上
         * METHOD       -- 方法上
         * PARAMETER    -- 參數上
         * CONSTRUCTOR  -- 構造函數上
         * LOCAL_VARIABLE -- 局部變量
         * ANNOTATION_TYPE   -- Annotation類型上
         * PACKAGE           -- 包上
         *
      * 3.Documented    -- 讓這個Annotation類型的信息可以顯示在API說明文檔上;沒有添加的話,使用javadoc生成的API文件找不到這個類型生成的信息
 */

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AssertOK {

    String isLogin() default "false";

}

2.再建立個攔截器,攔截目標方法並在目標方法先後執行操做web

package com.mb.aop;
import com.sun.istack.internal.logging.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.TypeVariable;

@Component
@Aspect
public class AssertOKAspectj {

    private Logger logger = Logger.getLogger(this.getClass());

    @Pointcut("@annotation(com.mb.aop.AssertOK)")  //表示全部帶有AssertOK的註解
    public void point(){

    }

//    @Pointcut("execution(* com.mb..*.*(..))")  //表示攔截全部com.mb包及子包下的全部的方法
//    public void point(){
//
//    }

    @Around(value = "point()")
    public Object assertAround(ProceedingJoinPoint pjp){

        //判斷註解標識若是不爲false則,進行登陸
        Class<?> aClass = pjp.getTarget().getClass(); //先獲取被織入加強處理的目標對象,再獲取目標類的clazz
        String methodName = pjp.getSignature().getName(); //先獲取目標方法的簽名,再獲取目標方法的名
        logger.info("methodName: "+methodName);  // 輸出目標方法名
        Class[] parameterTypes = ((MethodSignature) pjp.getSignature()).getParameterTypes(); //獲取目標方法參數類型
        Object[] args = pjp.getArgs();  //獲取目標方法的入參
        for (int i = 0; i < args.length; i++) {
            logger.info("argsName: "+args[i]); //輸出目標方法的參數
        }
        try {
            Method method = aClass.getMethod(methodName, parameterTypes);  //獲取目標方法
            AssertOK annotation = method.getAnnotation(AssertOK.class);  //獲取方法上的註解
            annotation.isLogin();  //獲取註解函數值
            long starttime = System.currentTimeMillis();
            Object proceed = pjp.proceed();  //執行目標方法
            long exctime = System.currentTimeMillis() - starttime;
            logger.info("執行時間:"+exctime + "毫秒");
            logger.info("proceed: "+proceed);  //打印目標方法的return結果
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return "aop的返回值";
    }

}

3.這裏爲了多場景驗證,我建立了2個目標類分別是:Login 、QueryAccount spring

package com.mb.request;

import com.mb.aop.AssertOK;
import org.springframework.stereotype.Component;

@Component
public class Login {

    @AssertOK(isLogin = "ture")
    public String login(String username,String password){
        System.out.println(username+" 登陸成功 "+", 登陸的密碼是 "+password);
        return "登陸成功";
    }

    @AssertOK(isLogin = "false")
    public String loginOnline(String name,String pwd){
        String login = login(name, pwd);
        System.out.println("login 的返回值:"+login);
        return "loginOnline 成功";
    }
}
package com.mb.request;

import com.mb.aop.AssertOK;
import org.springframework.stereotype.Component;

@Component
public class QueryAccount {

    @AssertOK
    public String queryAccount(){

        System.out.println("帳戶查詢成功....");
        return "success";
    }
}

4.配置spring包掃描和自動代碼配置,這裏默認使用的是jdk動態代理apache

<?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:context="http://www.springframework.org/schema/context"
       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.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 自動掃描web包 ,將帶有註解的類 歸入spring容器管理 -->
    <context:component-scan base-package="com.mb"></context:component-scan>

    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

5.最後就是須要咱們把pom.xml文件中添加aspectj和spring核心包等app

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mb</groupId>
    <artifactId>aspectjdemo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.20.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.1</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>4.3.7.RELEASE</version>
        <scope>test</scope>
    </dependency>
</dependencies>
</project>

6.以上搞定,下面咱們來作測試,驗證配置的aop是否生效maven

package com.mb.request;

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(locations = {"classpath*:**/applicationContext*.xml"})
public class RequestTest {

    @Autowired
    Login login;
    @Autowired
    QueryAccount queryAccount;

    @Test
    public void loginTest(){
        login.loginOnline("米小圈","123456");
    }
}

7.測試結果:函數

二月 27, 2019 12:04:01 上午 [com.mb.aop.AssertOKAspectj]  invoke0
信息: methodName: loginOnline
二月 27, 2019 12:04:01 上午 [com.mb.aop.AssertOKAspectj]  invoke0
信息: argsName: 米小圈
二月 27, 2019 12:04:01 上午 [com.mb.aop.AssertOKAspectj]  invoke0
信息: argsName: 123456
米小圈 登陸成功 , 登陸的密碼是 123456
login 的返回值:登陸成功
二月 27, 2019 12:04:01 上午 [com.mb.aop.AssertOKAspectj]  invoke0
信息: 執行時間:15毫秒
二月 27, 2019 12:04:01 上午 [com.mb.aop.AssertOKAspectj]  invoke0
信息: proceed: loginOnline 成功
相關文章
相關標籤/搜索