【Spring-Framework】Spring-framework文檔閱讀筆記——Core(下)

5.1. AOP Concepts——AOP概念

  • Aspect: modularization of a concern that cuts across multiple classes. 翻譯爲切面:對於橫跨多個類的關注點的模塊化。舉例來講,開啓事務這個操作要在數據庫增刪改之前執行,這個操作要插入在所有增刪改操作之前,那麼開啓事務這個操作就是橫跨了多個類的一個關注點,他就是一個切面。
  • Join point: A point during the execution of a program. 翻譯爲連接點:程序運行中的一個點。舉例:一個方法就是一個連接點,spring中連接點指的就是方法。在AOP中,我們需要將切面放在某個方法之前或者之後等等,就是將切面與方法進行連接,使程序可以依次執行,而每個方法都可以進行連接操作,所以每個方法就都是一個連接點。
  • Advice: Action taken by an aspect at a particular join point. 翻譯爲通知: 切面在連接點執行的動作。比如之前提到開啓事務這個操作,就是切面在連接點執行的動作,就是通知,指的是切面具體乾的事兒是啥。
  • Pointcut: A predicate that matches join points. 翻譯爲切入點:匹配連接點斷言。雖然每個連接點都可以連接切面,但實際場景中,我們僅僅需要對某些連接點插入切面,切入點的簡單意思就是去匹配符合條件的、需要進行切面插入的連接點。
  • Introduction: Declaring additional methods or fields on behalf of a type. 翻譯爲引入:爲類聲明額外的方法和字段。這個功能可以幫助一個類成爲某一個其實際上沒有實現的接口的實現類。
  • Target object: An object being advised by one or more aspects. 翻譯爲目標對象:被切面通知的對象。例如DAO對象裏的增刪改方法需要被事務切面通知,這個DAO對象就是目標對象。
  • AOP proxy: An object created by the AOP framework in order to implement the aspect contracts. 翻譯爲AOP代理:AOP框架創建的用於實現切面的代理對象
  • Weaving: linking aspects with other application types or objects to create an advised object. 翻譯爲編織:將切面與目標類聯繫在一起從而創建目標對象。指的是這個動作。

5.4. @AspectJ support

5.4.2. Declaring an Aspect

With @AspectJ support enabled, any bean defined in your application context with a class that is an @AspectJ aspect (has the @Aspect annotation) is automatically detected by Spring and used to configure Spring AOP.

這也就是說,切面需要註冊進容器裏才能成功被使用

5.4.3. Declaring a Pointcut

注意,spring裏切面本身不能再被其他切面切入,就是說其方法只能作爲advice,不能作爲pointcut,也就是說不能套娃。

5.5.4. Declaring Advice

  • Access to the Current JoinPoint
    由於ProceedingJoinPoint可以通過getArgs獲取參數,因此可以對參數進行手動修改,例如
@Around(value = "getBlogPt()")
    public Object getBlogAround(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("before getBlog");
        Author author = (Author) pjp.getArgs()[0];
        author.setId(author.getId()+1);
        Object object=pjp.proceed();
        System.out.println("after getBlog 我來看看這個blog");
        System.out.println(object);
        return object;
    }
  • Passing Parameters to Advice
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation() && args(account,..)")
public void validateAccount(Account account) {
    // ...
}

The args(account,…) part of the pointcut expression serves two purposes. First, it restricts matching to only those method executions where the method takes at least one parameter, and the argument passed to that parameter is an instance of Account. Second, it makes the actual Account object available to the advice through the account parameter.

  • Advice Order

Given two aspects, the aspect returning the lower value from Ordered.getValue() (or the annotation value) has the higher precedence.

5.4.5. Introductions

下面代碼的意思就是:com.xzy.myapp.service包下面所有類的實現類,都又實現了一個UsageTracked接口,實現方法由DefaultUsageTracked.class決定

@DeclareParents(value="com.xzy.myapp.service.*+", defaultImpl=DefaultUsageTracked.class)
public static UsageTracked mixin;

這個功能只會影響容器創建的com.xzy.myapp.service.*類對象,可以成功類型轉換;不會影響手動new出來的對象,類型轉換會失敗。

5.4.6. Aspect Instantiation Models

文檔裏說

@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")

In the preceding example, the effect of the ‘perthis’ clause is that one aspect instance is created for each unique service object that executes a business service (each unique object bound to ‘this’ at join points matched by the pointcut expression).

但我發現, 如果切面的作用域是prototype,那就是每個目標類對象都有一個對應的切面對象啊。
不過我發現,如果某個切面帶有下面的註解,那麼這個切面類裏的advice通知方法就只能對註解裏寫的這個PointCut生效了

@Aspect("perthis(execution(* service.BlogServiceImp.getBlog(..)))")

5.5. Schema-based AOP Support

Within your Spring configurations, all aspect and advisor elements must be placed within an <aop:config> element (you can have more than one <aop:config> element in an application context configuration). An <aop:config> element can contain pointcut, advisor, and aspect elements (note that these must be declared in that order).

5.5.2. Declaring a Pointcut

示例代碼好像有錯,下面代碼不應該是this,而應該是args

<aop:config>
    <aop:aspect id="myAspect" ref="aBean">
        <aop:pointcut id="businessService"
            expression="execution(* com.xyz.myapp.service.*.*(..)) && this(service)"/>
        <aop:before pointcut-ref="businessService" method="monitor"/>
   </aop:aspect>
</aop:config>

5.5.6. Advisors

Advisor: An advisor is like a small self-contained aspect that has a single piece of advice.
可以翻譯成通知者,文檔給出的解釋是,通知者是一個只有一個通知Advice自管理切面

  • 首先,Advisor是一個與切面,他又叫通知者,說明他和普通切面一樣,包含着各種通知;
  • 其次,他的名字叫做通知者,而且文檔中說了他是自管理的,說明這個切面不需要我們手動指定aop:before之類的通知配置,而可以根據情況或者配置自動執行相應的通知操作。

例如事務管理操作

    <!-- 配置事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 配置事務的通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 配置事務的屬性
                isolation:用於指定事務的隔離級別。默認值是DEFAULT,表示使用數據庫的默認隔離級別。
                propagation:用於指定事務的傳播行爲。默認值是REQUIRED,表示一定會有事務,增刪改的選擇。查詢方法可以選擇SUPPORTS。
                read-only:用於指定事務是否只讀。只有查詢方法才能設置爲true。默認值是false,表示讀寫。
                timeout:用於指定事務的超時時間,默認值是-1,表示永不超時。如果指定了數值,以秒爲單位。
                rollback-for:用於指定一個異常,當產生該異常時,事務回滾,產生其他異常時,事務不回滾。沒有默認值。表示任何異常都回滾。
                no-rollback-for:用於指定一個異常,當產生該異常時,事務不回滾,產生其他異常時事務回滾。沒有默認值。表示任何異常都回滾。
        -->
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED" read-only="false"/>
            <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
    </tx:advice>

    <!-- 配置aop-->
    <aop:config>
        <!-- 配置切入點表達式-->
        <aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"/>
        <!--建立切入點表達式和事務通知的對應關係 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>
    </aop:config>

5.6. Choosing which AOP Declaration Style to Use

5.6.1. Spring AOP or Full AspectJ?

If you need to advise objects not managed by the Spring container (such as domain objects, typically), you need to use AspectJ.

Spring只能對ioc容器中的對象進行切面編程,假如我們對Author類的getName添加了before advice,第一個getName就能執行before advice,第二個就不行

        Author author = ac.getBean("author1", Author.class);
        author.getName();
        new Author().getName();

5.6.2. @AspectJ or XML for Spring AOP?

XML配置的缺點1:切面的聲明和使用分在了兩個地方
缺點2:沒法合併多個定義好的切入點表達式

5.8. Proxying Mechanisms

5.8.1. Understanding AOP Proxies

在Spring AOP代理裏面提到了self-invocation——自調用,比如說現在有一個類聲明如下

public class SimplePojo implements Pojo {
    public void foo() {
        // this next method invocation is a direct call on the 'this' reference
        this.bar();
    }
    public void bar() {
        // some logic...
    }
}

然後我們對這個SimplePojo的全部方法進行代理

class MyAdvice implements MethodBeforeAdvice {
            @Override
            public void before(Method method, Object[] objects, Object o) throws Throwable {
                System.out.println("before");
            }
        }
ProxyFactory factory = new ProxyFactory(new SimplePojo());
factory.addInterface(Pojo.class);
factory.addAdvice(new MyAdvice());
Pojo pojo=(Pojo)factory.getProxy();
pojo.foo();

我們會發現,foo方法被代理了,但由於foo方法還調用了bar方法,foo方法裏的bar方法並不是代理版本的;這個就是代理的自調用引出的問題。
文檔裏給出的解決方法是把容器維護的代理對象告訴給這個被代理對象。

5.9. Programmatic Creation of @AspectJ Proxies

這個就是編程實現AOP功能,挺簡單的,關鍵的就是幾個Advice接口

5.10. Using AspectJ with Spring Applications

我沒用過AspectJ,所以這章看的雲裏霧裏

5.10.1. Using AspectJ to Dependency Inject Domain Objects with Spring

Spring只能對容器創建的對象進行依賴注入,而通過使用@Configurable,可以對new出來的對象進行依賴注入。
專門寫了一篇博客,文檔中提到,爲了這個功能起作用,the annotated types must be woven with the AspectJ weaver. You can either use a build-time Ant or Maven task to do this (see, for example, the AspectJ Development Environment Guide) or load-time weaving (see Load-time Weaving with AspectJ in the Spring Framework).
也就是說要麼使用Maven進行編譯,要麼通過LTW進行實現

5.10.3. Configuring AspectJ Aspects by Using Spring IoC

下面是註冊特定的切面類的方法,也就是說只註冊了annoAspect這個切面,其餘切面不起作用

    <bean id="annoAspect" class="myAspect.AnnoAspect"/>
    <aop:aspectj-autoproxy>
        <aop:include name="annoAspect"/>
    </aop:aspectj-autoproxy>

5.10.4. Load-time Weaving with AspectJ in the Spring Framework

XML配置不好使,但註解配置好使,代碼

6. Spring AOP API

代碼demo
就是使用spring對對象進行代理,裏面涉及了advisor等應用

6.7. Manipulating Advised Objects

If you added an interceptor or other advice type, Spring wrapped this in an advisor with a pointcut that always returns true.

就是說所有的advice在實際應用的時候都會被包裝成一個Advisor

6.8 using Auto-proxy facility

不需要對每個目標對象手動配置,而是對目標對象自動生成代理對象

BeanNameAutoProxy

根據名稱對目標對象進行代理

DefaultAdvisorAutoProxy

自動搜索容器內的Advisor,然後根據這些AdvisorPointCut對容器內的對象進行代理

6.9 using TargetResource

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章