[Spring+SpringMVC+Mybatis]框架學習筆記(五):SpringAOP_顧問

上一章:[Spring+SpringMVC+Mybatis]框架學習筆記(四):Spring實現AOP
下一章:[Spring+SpringMVC+Mybatis]框架學習筆記(六):Spring_AspectJ實現AOPhtml

第5章 SpringAOP_顧問

對第4章Spring實現AOP的缺點的思考:java

  • 一個代理只能代理一個bean,意味着在實際應用中要定義多個代理;(經過默認advisor自動代理生成器來解決)
  • 從容器中獲取對象是經過代理的bean的id,而不是咱們在容器中定義的目標對象的id;(經過默認advisor自動代理生成器來解決)
  • 通知只能切入到目標類的全部的方法,不能指定某些方法。(經過顧問對通知的封裝實現)

5.1 顧問Advisor

它將通知進行了包裝,根據通知的不一樣類型,在不一樣的時間點,將切面織入到指定的目標對象的某些鏈接點。正則表達式

PointCutAdvisor 顧問的一種,它是一個接口,有兩個實現類:spring

  • NameMatchMethodPointCutAdvisor 名稱匹配方法切入點顧問
  • RegexpMethodPointCutAdvisor 正則表達式方法切入點顧問

複習正則表達式:
(*) 星號:匹配前面的子表達式任意次 例如:ao* 能匹配 a ao aoo aooooo
(+) 加號:匹配前面的子表達式一次或屢次 例如:ao+ 能匹配 ao aoo aooooo
(.) 點 :匹配任意字符 除「\r\n」以外
.* 表明任意的一個字符串 .*add.* 表明包含add字符的任意字符串app

實例:框架

利用實例4.5的目標類接口、目標類、通知,實現切入到目標類的指定的方法。學習

1)配置文件測試

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

    <!-- 註冊服務類,並描述依賴關係 -->
    <bean id="studentService" class="com.steven.spring.sysmgr.service.impl.StudentService"></bean>
    
    <!-- 註冊前置通知 -->
    <bean id="beforeAdvice" class="com.steven.spring.sysmgr.advice.MyBeforeAdvice"></bean>
    
    <!-- 註冊後置通知 -->
    <bean id="afterAdvice" class="com.steven.spring.sysmgr.advice.MyAfterAdvice"></bean>
    
    <!-- 註冊環繞通知 -->
    <bean id="aroundAdvice" class="com.steven.spring.sysmgr.advice.MyAroundAdvice"></bean>
    
    <!-- 註冊異常通知 -->
    <bean id="throwingAdvice" class="com.steven.spring.sysmgr.advice.MyThrowingAdvice"></bean>
    
    <!-- 註冊一個名稱匹配方法切入點顧問 -->
    <!-- 顧問Advisor比通知Advice多了一個指定方法的步驟 -->
    <bean id="beforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <property name="advice" ref="beforeAdvice"/>
        <!-- 限定單個目標方法 -->
        <property name="mappedName" value="addStudent"/>
        <!-- 限定多個目標方法 -->
        <!-- 方法1 -->
        <!-- <property name="mappedNames" value="addStudent,updateStudent"/> -->
        <!-- 方法2 -->
        <!-- <property name="mappedNames">
            <array>
                <value>addStudent</value>
                <value>updateStudent</value>
            </array>
        </property> -->
        <!-- 方法3 -->
        <!-- <property name="mappedNames" value="*Student"/> -->
        
    </bean>

    <!-- 註冊前置顧問代理生成器 -->
    <bean id="myBeforeAdvisorProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="studentService"/>
        <property name="interceptorNames" value="beforeAdvisor"/>
    </bean>
    
    <!-- 註冊一個正則表達式方法切入點顧問 -->
    <bean id="afterAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice" ref="afterAdvice"/>
        <!--限定單種方法-->
        <property name="pattern" value=".*add.*"/>
        <!-- 限定多種 -->
        <property name="patterns" value=".*add.*,.*del.*"/>
    </bean>
    
    <!-- 註冊後置顧問代理生成器 -->
    <bean id="myAfterAdvisorProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="studentService"/>
        <property name="interceptorNames" value="afterAdvisor"/>
    </bean>
    
</beans>

2)測試代理

package com.steven.spring.sysmgr.test;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.steven.spring.sysmgr.entity.Student;
import com.steven.spring.sysmgr.service.IStudentService;

/**
 * 測試顧問
 * @author chenyang
 *
 */
public class AdvisorTest {
    private ApplicationContext ac = null;
    
    @Before
    public void init(){
        ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    }
    
    //測試前置顧問,指定某些方法,使用名稱匹配切入點方法顧問來實現
    @Test
    public void testBeforeAdvisor(){
        IStudentService studentService = (IStudentService) ac.getBean("myBeforeAdvisorProxy");
        studentService.addStudent(new Student());
        studentService.updateStudent(new Student());//修改功能的前置通知不能被打印
    }
    
    //測試後置顧問,指定某些方法,使用正則表達式切入點方法顧問來實現
    @Test
    public void testAfterAdvisor(){
        IStudentService studentService = (IStudentService)ac.getBean("myAfterAdvisorProxy");
        studentService.addStudent(new Student());
        studentService.delStudent(1);
        studentService.updateStudent(new Student());
    }
    
}

5.2 自動代理生成器

Spring提供了自動代理生成器來解決要定義多個代理生成器的問題,有兩種方式:code

  • 默認advisor自動代理生成器(目標對象爲配置文件中配置的全部的目標對象bean,並且爲配置文件裏面全部的advisor自動生成代理); ---> 籠統
  • bean名稱自動代理生成器(能夠指定某些目標對象(bean),並且能夠指定某些切面的實現(advise/advisor)) 。 ---> 精確

總結:

第4-5章中各類技術的運用,無非是爲了一個目標:將咱們編寫的切面的實現(通知/顧問)織入到某些類的某些方法中。

實例:

利用實例4.5的目標類接口、目標類、通知,實現切入到目標類的指定的方法。

1)配置文件

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

    <!-- 註冊服務類,並描述依賴關係 -->
    <bean id="studentService" class="com.steven.spring.sysmgr.service.impl.StudentService"></bean>
    
    <!-- 註冊前置通知 -->
    <bean id="beforeAdvice" class="com.steven.spring.sysmgr.advice.MyBeforeAdvice"></bean>
    
    <!-- 註冊後置通知 -->
    <bean id="afterAdvice" class="com.steven.spring.sysmgr.advice.MyAfterAdvice"></bean>
    
    <!-- 註冊環繞通知 -->
    <bean id="aroundAdvice" class="com.steven.spring.sysmgr.advice.MyAroundAdvice"></bean>
    
    <!-- 註冊異常通知 -->
    <bean id="throwingAdvice" class="com.steven.spring.sysmgr.advice.MyThrowingAdvice"></bean>
    
    <!-- 註冊一個名稱匹配方法切入點顧問 -->
    <!-- 顧問Advisor比通知Advice多了一個指定方法的步驟 -->
    <bean id="beforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <property name="advice" ref="beforeAdvice"/>
        <property name="mappedName" value="addStudent"/>
    </bean>

    <!-- 註冊一個正則表達式方法切入點顧問 -->
    <bean id="afterAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice" ref="afterAdvice"/>
        <property name="pattern" value=".*add.*"/>
    </bean>
    
    <!-- 默認Advisor自動代理生成器,目標對象爲配置文件中註冊的全部的目標對象,advisor爲配置文件中全部的advisor -->
    <!-- <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean> -->
    
    <!-- bean名稱自動代理生成器,不只能夠指定目標對象,還能夠指定advise/advisor(注意:這裏均可以!) -->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames" value="studentService"/>
        <property name="interceptorNames" value="beforeAdvisor"/>
    </bean>
    
</beans>

2)測試默認Advisor自動代理生成器

package com.steven.spring.sysmgr.test;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.steven.spring.sysmgr.entity.Student;
import com.steven.spring.sysmgr.service.IStudentService;

public class DefaultAdvisorAutoProxyCreator {
    private ApplicationContext ac = null;
    
    @Before
    public void init(){
        ac = new ClassPathXmlApplicationContext("applicationContextForAutoProxy.xml");
    }
    
    //測試默認顧問自動代理生成器
    @Test
    public void testDefaultAdvisorAutoProxyCreator(){
        // 注意:這裏是直接取容器中定義的目標對象的id,再也不使用代理生成器的id
        IStudentService studentService = (IStudentService) ac.getBean("studentService");
        studentService.addStudent(new Student());
        studentService.updateStudent(new Student());//修改功能的前置通知不能被打印
    }
}

3)測試bean名稱自動代理生成器

package com.steven.spring.sysmgr.test;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.steven.spring.sysmgr.entity.Student;
import com.steven.spring.sysmgr.service.IStudentService;

public class BeanNameAutoProxyCreator {
    private ApplicationContext ac = null;
    
    @Before
    public void init(){
        ac = new ClassPathXmlApplicationContext("applicationContextForAutoProxy.xml");
    }
    
    //測試bean名稱自動代理生成器
    @Test
    public void testBeanNameAutoProxyCreator(){
        IStudentService studentService = (IStudentService) ac.getBean("studentService");
        studentService.addStudent(new Student());
        studentService.updateStudent(new Student());
    }
}

上一章:[Spring+SpringMVC+Mybatis]框架學習筆記(四):Spring實現AOP
下一章:[Spring+SpringMVC+Mybatis]框架學習筆記(六):Spring_AspectJ實現AOP

相關文章
相關標籤/搜索