AOP 增強方法


Spring AOP 提供了 5 種類型的通知,它們分別是 Before Advice(前置通知)、After Returning Advice(后置通知)、Interception Around Advice(周圍通知)、Throws Advice(異常通知)和 Introduction Advice(引介通知)。

Spring AOP的增強類型
首先先了解一下增強接口的繼承關系:

下面分別進行介紹。

如上圖所示:
其中帶Spring標志的是Spring定義的擴展增強接口
其中帶aopalliance標志的是AOP聯盟所定義的接口
 
按照增加在目標類方法連接點的位置可以將增強划分為以下五類:
  • 前置增強   (org.springframework.aop.BeforeAdvice)   表示在目標方法執行前來實施增強
  • 后置增強   (org.springframework.aop.AfterReturningAdvice)   表示在目標方法執行后來實施增強
  • 環繞增強   (org.aopalliance.intercept.MethodInterceptor)   表示在目標方法執行前后同時實施增強
  • 異常拋出增強   (org.springframework.aop.ThrowsAdvice)   表示在目標方法拋出異常后來實施增強
  • 引介增強   (org.springframework.aop.introductioninterceptor)   表示在目標類中添加一些新的方法和屬性
其中,引介增強是一種特殊的增強。他可以在目標類中添加屬性和方法,通過攔截定義一個接口,讓目標代理實現這個接口。他的連接點是類級別的,而前面的幾種則是方法級別的。
其中,環繞增強是AOP聯盟定義的接口,其他四種增強接口則是Spring定義的接口。
 
其實,AOP增強很簡單:
通過實現這些增強接口,在實現這些接口的方法當中定義橫切邏輯,然后通過配置Spring的配置文件就可以完成將增強織入到目標方法當中了。
 
補充:增強既包含了橫切邏輯同時又包含了部分連接點信息。
 

前置增強:

import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;

import java.lang.reflect.Method;

public class Main{
    public static void main(String[] args) {
        //1、不使用xml配置實例化
        Worker target=new DigWorker();
        BeforeAdvice advice=new WearingBeforeAdvice();
        //Spring提供的代理工廠
        ProxyFactory pFactory=new ProxyFactory();
//        //指定做優化,又將使用cglib動態
//        pFactory.setOptimize(true);
//
//        //指定對接口進行代理,通過JDK動態代理
//        pFactory.setInterfaces(target.getClass().getInterfaces());

        //設置代理目標,默認使用Cglib動態代理
        pFactory.setTarget(target);

        //為代理目標添加前置增強,這里會為目標的每個方法都增加增強
        pFactory.addAdvice(advice);
        //生成代理實例
        Worker proxy=(Worker)pFactory.getProxy();
        proxy.getTool("鑽機");
        proxy.digSomething("煤炭");
        proxy.initWork();
    }
}

interface Worker {
    void getTool(String tool);
    void digSomething(String type);
    void initWork();
}

class DigWorker implements Worker{

    @Override
    public void getTool(String tool) {
        System.out.println("---------------調用方法--------------");
        System.out.println("領取工具:"+tool);
        // throw new RuntimeException("運行異常");
    }

    @Override
    public void digSomething(String type) {
        System.out.println("---------------調用方法--------------");
        System.out.println("開始賣力挖取:"+type);

    }

    @Override
    public void initWork() {
        System.out.println("生成一個DigWorker實例");
    }
}

class WearingBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
       if(arg1.length>0) {
           String thing = (String) arg1[0];
           System.out.println("--------------進行前置增強---------------");
           System.out.println("得到" + thing + "之前先穿上工作服!!");
       }else{
           System.out.println("--------------進行前置增強2---------------");
       }
    }
}
--------------進行前置增強---------------
得到鑽機之前先穿上工作服!!
---------------調用方法--------------
領取工具:鑽機
--------------進行前置增強---------------
得到煤炭之前先穿上工作服!!
---------------調用方法--------------
開始賣力挖取:煤炭
--------------進行前置增強2---------------
生成一個DigWorker實例

前置和后置:

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.lang.reflect.Method;

public class Main{
    public static void main(String[] args) {
        //2、下面使用Spring的xml配置實例化
        ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
        //worker1帶前置和后置增強
        Worker worker1=(Worker)ctx.getBean("worker1");
        System.out.println("worker1進入工作:");
        worker1.getTool("鋤頭");
    }
}

interface Worker {
    void getTool(String tool);
    void digSomething(String type);
    void initWork();
}

class DigWorker implements Worker{

    @Override
    public void getTool(String tool) {
        System.out.println("---------------調用方法--------------");
        System.out.println("領取工具:"+tool);
        // throw new RuntimeException("運行異常");
    }

    @Override
    public void digSomething(String type) {
        System.out.println("---------------調用方法--------------");
        System.out.println("開始賣力挖取:"+type);

    }

    @Override
    public void initWork() {
        System.out.println("生成一個DigWorker實例");
    }
}

class WearingBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
       if(arg1.length>0) {
           String thing = (String) arg1[0];
           System.out.println("--------------進行前置增強---------------");
           System.out.println("得到" + thing + "之前先穿上工作服!!");
       }else{
           System.out.println("--------------進行前置增強2---------------");
       }
    }
}

class WeaningAfterAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object arg0, Method arg1, Object[] arg2,
                               Object arg3) throws Throwable {
        System.out.println("--------------進行后置增強---------------");
        System.out.println("工作結束,請先脫掉工作服");
    }
}

benas文件:

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    <!-- 要進行增強的目標 -->
    <bean id="target" class="com.company.DigWorker" init-method="initWork"/>

    <!-- 前置增強的方法 -->
    <bean id="beforeAdvice" class="com.company.WearingBeforeAdvice" />
    <!-- 后置增強的方法 -->
    <bean id="afterAdvice" class="com.company.WeaningAfterAdvice" />

    <!--同時設置前置增強和后置增強方法  -->
    <bean id="worker1" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.company.Worker" p:interceptorNames="beforeAdvice,afterAdvice"
          p:target-ref="target" lazy-init="true"/>
</beans>

Result:

生成一個DigWorker實例
worker1進入工作:
--------------進行前置增強---------------
得到鋤頭之前先穿上工作服!!
---------------調用方法--------------
領取工具:鋤頭
--------------進行后置增強---------------
工作結束,請先脫掉工作服

 

環繞增強:

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.aopalliance.intercept.MethodInterceptor;


public class Main{
    public static void main(String[] args) {
        //2、下面使用Spring的xml配置實例化
        ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
        //work2帶環繞增強
        Worker worker2=(Worker)ctx.getBean("worker2");
        System.out.println("worker2進入工作:");
        worker2.getTool("鑽機");
    }
}

interface Worker {
    void getTool(String tool);
    void digSomething(String type);
    void initWork();
}

class DigWorker implements Worker{

    @Override
    public void getTool(String tool) {
        System.out.println("---------------調用方法--------------");
        System.out.println("領取工具:"+tool);
        // throw new RuntimeException("運行異常");
    }

    @Override
    public void digSomething(String type) {
        System.out.println("---------------調用方法--------------");
        System.out.println("開始賣力挖取:"+type);

    }

    @Override
    public void initWork() {
        System.out.println("生成一個DigWorker實例");
    }
}

class WearingInterceptor implements MethodInterceptor{
    @Override
    public Object invoke(MethodInvocation arg0) throws Throwable {
        Object[] args=arg0.getArguments();//目標方法入參
        String toolname=(String)args[0];
        System.out.println("--------------環繞增強開始---------------");
        System.out.println("得到"+toolname+"之前先穿上工作服");
        Object object=arg0.proceed();
        System.out.println("工作結束,請先脫掉工作服");
        System.out.println("--------------環繞增強結束---------------");
        return object;
    }
}

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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    <!-- 要進行增強的目標 -->
    <bean id="target" class="com.company.DigWorker" init-method="initWork"/>
    <!-- 環繞增強的方法 -->
    <bean id="aroundAdvice" class="com.company.WearingInterceptor" />
    <!--設置環繞增強方法  -->
    <bean id="worker2" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.company.Worker" p:interceptorNames="aroundAdvice"
          p:target-ref="target" lazy-init="true"/>
</beans>

Result:

生成一個DigWorker實例
worker2進入工作:
--------------環繞增強開始---------------
得到鑽機之前先穿上工作服
---------------調用方法--------------
領取工具:鑽機
工作結束,請先脫掉工作服
--------------環繞增強結束---------------

 

異常拋出增強:

import org.springframework.aop.ThrowsAdvice;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.lang.reflect.Method;

public class Main{
    public static void main(String[] args) throws Exception {
        //2、下面使用Spring的xml配置實例化
        ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
        //work3帶環繞增強
        Worker worker3=(Worker)ctx.getBean("worker3");
        System.out.println("worker3進入工作:");
        worker3.getTool("錘子");
    }
}

interface Worker {
    void getTool(String tool);
    void digSomething(String type);
    void initWork();
}

class DigWorker implements Worker{

    @Override
    public void getTool(String tool) {
        System.out.println("---------------調用方法--------------");
        System.out.println("領取工具:"+tool);
        throw new RuntimeException("運行異常");
    }

    @Override
    public void digSomething(String type) {
        System.out.println("---------------調用方法--------------");
        System.out.println("開始賣力挖取:"+type);

    }

    @Override
    public void initWork() {
        System.out.println("生成一個DigWorker實例");
    }
}


class WeaningThrowAdvice implements ThrowsAdvice {
    public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {
        System.out.println("--------------------");
        System.out.println("method:"+method.getName());
        System.out.println("拋出異常"+ex.getMessage());
        System.out.println("成功回滾事務");
    }
}

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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    <!-- 要進行增強的目標 -->
    <bean id="target" class="com.company.DigWorker" init-method="initWork"/>

    <!-- 異常拋出增強的方法  -->
    <bean id="throwAdvice" class="com.company.WeaningThrowAdvice" />

    <!--設置異常拋出增強方法  proxyTargetClass="true",使用CgLib代理-->
    <bean id="worker3" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="throwAdvice"
          p:target-ref="target"
          p:proxyTargetClass="true"/>
</beans>

Result:

生成一個DigWorker實例
worker3進入工作:
---------------調用方法--------------
領取工具:錘子
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
    at com.company.DigWorker$$EnhancerBySpringCGLIB$$b3caca85.getTool(<generated>)
    at com.company.Main.main(Main.java:18)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.lang.IllegalAccessException: Class org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor can not access a member of class com.company.WeaningThrowAdvice with modifiers "public"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
    at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invokeHandlerMethod(ThrowsAdviceInterceptor.java:145)
    at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:130)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656)

 

http://blog.csdn.net/icarus_wang/article/details/51737474

http://www.kancloud.cn/evankaka/springlearning/119668


免責聲明!

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



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