Spring筆記07(Spring AOP的通知advice和顧問advisor)


1.Spring AOP的通知advice

01.接口代碼:

package cn.pb.dao;

public interface UserDao {
    //主業務
    String add();
    //主業務
    void del();
}

 

02.實現類代碼:

package cn.pb.dao;

public class UserDaoImpl implements UserDao{
//主業務
public String add() {
//模擬異常
//int a=8/0;
System.out.println("add ok!");
return "新增成功!";
}
//主業務
public void del() {
System.out.println("del ok!");
}

03.增強通知類:

001.前置增強類:

package cn.pb.advices;
/**
 * 前置增強類 實現MethodBeforeAdvice接口
 * 在目標對象方法執行之前執行
 */

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforeAdvice implements MethodBeforeAdvice {
    /**
     *
     * @param method :目標方法
     * @param args  :目標方法參數
     * @param target :目標對象
     * @throws Throwable
     */
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("前置增強====================》");
    }
}

 

002.后置增強類:

package cn.pb.advices;
/**
 * 后置增強類 實現AfterReturningAdvice接口
 * 在目標對象方法執行之后執行
 */
import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterAdvice implements AfterReturningAdvice {
    /**
     *
     * @param target:目標對象
     * @param method :目標方法
     * @param args :目標方法參數
     * @param returnValue :目標方法返回值
     * @throws Throwable
     */
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("后置增強==================》");
    }
}

 

003.環繞增強類:

package cn.pb.advices;
/**
 * 環繞增強 :
 * 在前置通知 之后,
 * 后置通知之前執行環繞通知!
 */

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class AroundAdvice implements MethodInterceptor {
    /**
     * 在前置通知 之后,后置通知之前執行環繞通知!
     * 可以獲取方法的返回值,並且改變!
     * @param methodInvocation 方法的執行器, getMethod 包含了方法中的所有方法
     * @return
     */
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("執行方法之前的  環繞通知");
        //執行目標方法
        Object result= methodInvocation.proceed();
        if (result!=null){
            //對方法的返回值進行修改
            result="xiaoheihei";
        }
        System.out.println("執行方法之后的  環繞通知");
        return result;
    }
}

 

004.異常增強類:

package cn.pb.advices;

/**
 * 異常增強類:在目標方法出現異常的時候執行
 * 實現ThrowsAdvice接口
 */

import org.springframework.aop.ThrowsAdvice;



public class ExceptionAdvice implements ThrowsAdvice{
    public void throwsAdvice(){
        System.out.println("方法在執行過程中出現了異常!");
    }
}

 

04.applicationContext.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"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--01.配置目標對象-->
    <bean id="userDao" class="cn.pb.dao.UserDaoImpl"/>
    <!--02.配置通知-->
    <bean id="beforeAdvice" class="cn.pb.advices.BeforeAdvice"/>
    <bean id="afterAdvice" class="cn.pb.advices.AfterAdvice"/>
    <bean id="aroundAdvice" class="cn.pb.advices.AroundAdvice"/>

    <!--03.通過配置代理工廠bean,生成代理類,來把通知織入到目標對象
      問題:只能管理  通知!
         01.只能將切面織入到目標類的所有方法中!
         02.只能配置一個 目標對象
   -->
    <bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--注冊目標對象  如果nam為target 那么ref="userDao" -->
        <property name="targetName" value="userDao"/>
        <!--注冊通知-->
        <property name="interceptorNames" value="beforeAdvice,afterAdvice,aroundAdvice"/>

    </bean>



    <!--配置異常目標對象-->
    <bean id="userException" class="cn.pb.exceptionPackage.UserServiceImpl"/>
    <!--配置異常通知-->
    <bean id="myException" class="cn.pb.advices.ExceptionAdvice"/>

    <!--現在是一個service對應一個ProxyFactoryBean  這樣不可以!-->
    <bean id="exceptionProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--注冊目標對象 -->
        <property name="targetName" value="userException"/>
        <!--注冊通知-->
        <property name="interceptorNames">
            <array>
                <value>myException</value> <!--異常通知-->
            </array>
        </property>
        <!--代理類的優化  設置之后程序就會自動選擇是使用JDK動態代理還是使用cglib動態代理-->
        <property name="optimize" value="true"/>
        <!-- <property name="proxyTargetClass" value="true"/>
            proxyTargetClass:默認是false  ,默認執行jdk動態代理!
                              設置成true,強制執行cglib!
            optimize :  代理類的優化
                         有接口就是用jdk,沒有接口使用cglib動態代理-->
    </bean>
<!--
      我們的動態代理 (在程序運行期間,動態生成的代理類) 分為兩種方式:
         01.jdk     只能應用於實現接口的情況
         02.cglib   應用於實現接口和類的情況
         如果我們是接口的情況,使用jdk效率高!
         如果我們是類的情況,必須使用cglib!
        問題?
           程序  spring容器怎么知道我們是用的類還是接口??
          public class ProxyConfig implements Serializable
            private boolean proxyTargetClass = false;
            private boolean optimize = false;
            spring底層默認使用cglib! 現在我們的項目中使用的是接口!
            用spring默認的性能不高!
           proxyTargetClass 和optimize都是用來設置 我們使用的代理模式是jdk還是cglib!
           @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
       根據我們配置文件中 proxyTargetClass 和 optimize的配置
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
           根據目標對象返回對應的動態代理
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }
-->

</beans>

 

05.測試代碼:

package cn.pb;

import cn.pb.dao.UserDao;
import cn.pb.exceptionPackage.ServiceException;
import cn.pb.exceptionPackage.UserException;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAdvice {

    /**
     *  前置  后置 通知測試
     */

    @Test
    public    void   testBefore(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao service= (UserDao) context.getBean("userProxy");
        service.add();
        System.out.println("*************");
        service.del();
    }


    /**
     * 環繞 通知測試
     */

    @Test
    public    void   testAround(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao service= (UserDao) context.getBean("userProxy");
        String result= service.add();
        System.out.println(result);
        System.out.println("*************");
        service.del();
    }


    /**
     *  異常通知測試
     */

    @Test
    public    void   testException(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        ServiceException service= (ServiceException) context.getBean("exceptionProxy");
        try {
            service.chechUser("admins",25);
        } catch (UserException e) {
            e.printStackTrace();
        }

    }

}

 

 

2.Spring AOP的顧問advisor

01.readMe

顧問:在通知的基礎之上,在細化我們的aop切面!

通知和顧問都是切面的實現方式!
通知是顧問的一個屬性!

顧問會通過我們的設置,將不同的通知,在不通過的時間點,把切面
織入到不同的切入點!

PointCutAdvisor接口!
比較常用的兩個實現類:
NameMatchMethodPointcutAdvisor :根據切入點(主業務方法)名稱織入切面!
RegexpMethodPointcutAdvisor :根據自定義的正則表達式織入切面!


正則表達式中常用的三個運算符
.   任意單個字符
+   表示字符出現一次或者多次
*   表示字符出現0次或者多次

 

02.接口代碼:

package cn.pb.dao;

public interface UserDao {
    //主業務
    void  add();
    //主業務
    void  del();
}

 

03.實現類代碼:

package cn.pb.dao.impl;

import cn.pb.dao.UserDao;

public class UserDaoImpl implements UserDao{

    //主業務
    public void add() {
        System.out.println("add ok!");
    }
    //主業務
    public void del() {
        System.out.println("del ok!");
    }
}

 

04.增強類代碼:

package cn.pb.advices;
/**
 * 前置增強類 在目標方法執行之前 執行
 * 要實現MethodBeforeAdvice接口
 */

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforeAdvice implements MethodBeforeAdvice {
    /**
     * 在目標方法執行之前
     * @param method   目標方法
     * @param args    目標方法的參數列表
     * @param target    目標對象
     * @throws Throwable
     */
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("前置增強==============》");
    }
}

 

05.applicationContext.xml文件:

001.NameMatchMethodPointcutAdvisor :根據切入點(主業務方法)名稱織入切面!

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--01.配置目標對象-->
    <bean id="userDao" class="cn.pb.dao.impl.UserDaoImpl"/>
    <!--02.配置增強 通知-->
    <bean id="beforeAdvice" class="cn.pb.advices.BeforeAdvice"/>


    <!---配置顧問   實現了 在指定的主業務方法中 增強-->
    <bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <!--通知就是顧問中的一個屬性-->
        <property name="advice" ref="beforeAdvice"/>
        <!--配置切入點   這里的切入點指的是 方法的簡寫!-->
        <property name="mappedNames" value="add,del"/>
    </bean>

    <!--03.配置代理對象-->
    <bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--注冊目標對象-->
        <property name="target" ref="userDao"/>
        <!--注冊顧問-->
        <property name="interceptorNames" value="myAdvisor"/>
    </bean>

</beans>

 

002.RegexpMethodPointcutAdvisor :根據自定義的正則表達式織入切面!

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--01.配置目標對象-->
    <bean id="userDao" class="cn.pb.dao.impl.UserDaoImpl"/>
    <!--02.配置增強 通知-->
    <bean id="beforeAdvice" class="cn.pb.advices.BeforeAdvice"/>


    <!---配置顧問   實現了 在指定的主業務方法中 增強-->
    <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!--通知就是顧問中的一個屬性-->
        <property name="advice" ref="beforeAdvice"/>
        <!--配置切入點   這里的切入點指的是 方法的全限定方法名
          cn.pb.dao.impl.UserServiceImpl.add
           cn.pb.dao.impl.UserServiceImpl.del-->
        <!-- <property name="pattern" value=".*add.*"/>  匹配單個方法-->
        <!-- <property name="pattern" value=".*mpl.*"/>匹配多個方法-->
        <!--<property name="patterns" value=".*add.*,.*del.*"/>  匹配多個方法-->
        <property name="pattern" value=".*add.*|.*del.*"/>


</bean>

<!--03.配置代理對象-->
    <bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--注冊目標對象-->
        <property name="target" ref="userDao"/>
        <!--注冊顧問-->
        <property name="interceptorNames" value="myAdvisor"/>
    </bean>

</beans>

 

06.測試代碼:

package cn.pb;

import cn.pb.dao.UserDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUser {
    /**
     * 測試NameMatchMethodPointcutAdvisor
     */
    @Test
    public void testNameMethod(){
        ApplicationContext context=new
                ClassPathXmlApplicationContext("applicationContext.xml");
       UserDao proxy= (UserDao) context.getBean("userProxy");
       proxy.add();
        System.out.println("***************");
        proxy.del();
    }

    /**
     * 測試RegexpMethodPointcutAdvisor
     */
    @Test
    public void testRegexpMethod(){
        ApplicationContext context=new
                ClassPathXmlApplicationContext("regexp.xml");
        UserDao proxy= (UserDao) context.getBean("userProxy");
        proxy.add();
        System.out.println("***************");
        proxy.del();
    }
}

 


免責聲明!

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



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