Spring的AOP


一、實現自己的AOP

在之前一篇隨筆中已經詳細講解了java的動態代理機制,我們也知道了AOP的底層其實就是基於動態代理機制實現的,所以這里先自己實現一下AOP

public class DynamicProxy implements InvocationHandler
{
    // 要代理的對象
    private Object target;

    // 將構造方法禁用掉,不讓外部通過new來得到DynamicProxy對象
    private DynamicProxy()
    {
    };

    /**
     * 返回一個動態的代理對象
     * 
     * @param object
     * @return
     */
    public static Object newInstance(Object object)
    {
        DynamicProxy proxy = new DynamicProxy();
        proxy.target = object;
        //    通過Proxy的newProxyInstance方法來得到一個代理對象
        Object result = Proxy.newProxyInstance(object.getClass()
                .getClassLoader(), object.getClass().getInterfaces(), proxy);
        return result;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable
    {
//        //    只有方法名為add和delete時候才引入日志
//        if(method.getName().equals("add") || method.getName().equals("delete"))
//        {
//            Logger.logInfo("動態代理類");
//        }
        
        // 根據LogAnnotation來判斷,如果被標注了注解,則輸出日志
        if(method.isAnnotationPresent(LogAnnotation.class))
        {
            LogAnnotation log = method.getAnnotation(LogAnnotation.class);
            Logger.logInfo(log.value());
        }
        
        Object object = method.invoke(target, args);
        return object;
    }
}

就如上篇隨筆所說,動態代理類必須要實現InvocationHandler的這個接口,我們的這個類當然也要實現這個接口了。然后在里面定義了一個私有的Object屬性,表示我們要代理的對象。這里我們將這個類的構造方法禁用掉,使其不能通過外部直接new出來一個對象,然后我們寫一個newInstance的方法來給我們的代理對象賦初值,並且返回的就是我們的代理對象。我們看看在beans.xml中的配置文件

<!-- 如果要對static方法進行注入,可以通過factory-method屬性來制定方法名字,並通過構造函數的方式傳入參數 -->
        <bean id="userDAOProxy" class="com.xiaoluo.proxy.DynamicProxy" factory-method="newInstance">
            <constructor-arg ref="userDAO"/>
        </bean>

因為我們的DynamicProxy類的對象以及代理對象是通過static方法來進行注入的,因此我們如果要對其進行注入的話,需要通過 factory-method 這個屬性來給我們的靜態方法進行屬性注入,通過 <constructor-arg>來講參數傳遞進去,這樣我們的userDAOProxy就是一個代理對象了。

二、通過Annotation來配置我們的AOP

我們要將AOP的schema引入,如果使用注解的話,還要開啟AOP的自動代理

<?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-3.0.xsd">
        
        <!-- 通過annotation來進行bean的創建 -->
        <context:annotation-config/>
        <!-- 對以com.xiaoluo開頭的包進行掃描 -->
        <context:component-scan base-package="com.xiaoluo"/>
        <!-- 開啟AOP的自動代理,只要加入了@Aspect標簽就自動代理 -->
        <aop:aspectj-autoproxy/>
        
</beans>

然后我們來看看我們的切面類:

@Component("logAspect")    //    將該切面類由Spring托管
@Aspect    //    聲明該類是一個Aspect,切面類
public class LogAspect
{
    /**
     * execution(* com.xiaoluo.dao.*.add*(..))
     * 第一個*表示任意返回值
     * 第二個*表示com.xiaoluo.dao下的所有類
     * 第三個*表示所有以add開頭的方法
     * (..)表示方法接收的任何參數
     */
    /*
     * Before在方法執行前執行
     */
    @Before("execution(* com.xiaoluo.dao.*.add*(..))||" +
            "execution(* com.xiaoluo.dao.*.delete*(..))||" +
            "execution(* com.xiaoluo.dao.*.update*(..))")
    public void logStart(JoinPoint jp)
    {
        //    得到該JoinPoint的類
        System.out.println(jp.getTarget());
        //    得到該JoinPoint的方法
        System.out.println(jp.getSignature());
        //    得到該JoinPoint的方法的名字
        System.out.println(jp.getSignature().getName());
        Logger.logInfo("日志開始");
    }
    
    /*
     * After在方法執行只會執行
     */
    @After("execution(* com.xiaoluo.dao.*.add*(..))||" +
            "execution(* com.xiaoluo.dao.*.delete*(..))||" +
            "execution(* com.xiaoluo.dao.*.update*(..))")
    public void logEnd()
    {
        Logger.logInfo("日志結束");
    }
    
    /*
     * Around包含了這個方法的執行
     * 
     * Logger.logInfo("開始執行Around日志");
     * pjp.proceed();
     * Logger.logInfo("結束了Around日志");的執行順序為:
     * 
     * 首先執行 Logger.logInfo("開始執行Around日志");,接着執行方法,因為在方法執行要執行
     * Before,所以先執行完Before再執行方法,接着執行  Logger.logInfo("結束了Around日志");
     * 最后執行After
     * 
     */
    @Around("execution(* com.xiaoluo.dao.*.add*(..))||" +
            "execution(* com.xiaoluo.dao.*.delete*(..))||" +
            "execution(* com.xiaoluo.dao.*.update*(..))")
    public void logAround(ProceedingJoinPoint pjp) throws Throwable
    {
        Logger.logInfo("開始執行Around日志");
        pjp.proceed();
        Logger.logInfo("結束了Around日志");
    }
}

因為Spring的AOP使用的是第三方的jar包,所以我們這里還要引入三個AOP的jar文件:

aopalliance-1.0.jar
aspectjrt-1.7.3.jar
aspectjweaver-1.7.3.jar

這樣我們的基於注解的AOP就配置好可以使用了。

三、基於XML的AOP配置

如果基於XML的AOP配置,我們的beans.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: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-3.0.xsd">
        
        <!-- 通過annotation來進行bean的創建 -->
        <context:annotation-config/>
        <!-- 對以com.xiaoluo開頭的包進行掃描 -->
        <context:component-scan base-package="com.xiaoluo"/>
        <!-- 通過xml方式來配置AOP -->
        <aop:config>
            <!-- 聲明一個切面 -->
            <aop:aspect id="myLogAspect" ref="logAspect">
                <!-- 聲明在哪些位置我要加入這個切面 -->
                <aop:pointcut id="logPoint" expression="execution(* com.xiaoluo.dao.*.add*(..))||
                                                        execution(* com.xiaoluo.dao.*.delete*(..))||
                                                        execution(* com.xiaoluo.dao.*.update*(..))"/>
                <aop:before method="logStart" pointcut-ref="logPoint"/>
                <aop:after method="logEnd" pointcut-ref="logPoint"/>
                <aop:around method="logAround" pointcut-ref="logPoint"/>                
            </aop:aspect>
        </aop:config>        
</beans>

我們這里當然也要聲明我們的切面類:

@Component("logAspect")    //    將該切面類由Spring托管
public class LogAspect
{
    public void logStart(JoinPoint jp)
    {
        //    得到該JoinPoint的類
        System.out.println(jp.getTarget());
        //    得到該JoinPoint的方法
        System.out.println(jp.getSignature());
        //    得到該JoinPoint的方法的名字
        System.out.println(jp.getSignature().getName());
        Logger.logInfo("日志開始");
    }
    
    public void logEnd()
    {
        Logger.logInfo("日志結束");
    }
    
    public void logAround(ProceedingJoinPoint pjp) throws Throwable
    {
        Logger.logInfo("開始執行Around日志");
        pjp.proceed();
        Logger.logInfo("結束了Around日志");
    }
}

本篇隨筆主要記錄了自己實現AOP的配置以及基於Annotation和XML的方式來配置我們的AOP

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM