【spring原始碼學習】spring的AOP面向切面程式設計的實現解析

Love Lenka發表於2017-07-31

一:Advice(通知)
(1)定義在連線點做什麼,為切面增強提供織入介面。在spring aop中主要描述圍繞方法呼叫而注入的切面行為。
(2)spring定義了幾個時刻織入增強行為的介面
  =>org.springframework.aop.BeforeAdvice
   org.springframework.aop.MethodBeforeAdvice
  =>org.springframework.aop.AfterAdvice
   org.springframework.aop.AfterReturningAdvice
  =>org.springframework.aop.ThrowsAdvice

二:PointCut(切點)
(1)決定Advice應該作用那些連線點。也就是說透過PointCut來定義需要增強的方法集合。
(2)spring定義的PointCut的介面
  =>org.springframework.aop.Pointcut
  =>org.springframework.aop.TruePointcut
  => org.springframework.aop.support.JdkRegexpMethodPointcut
(3)相關介面。PointCut介面會返回兩個物件,一個ClassFilter,一個是MethodMatcher
  =>org.springframework.aop.ClassFilter    
  =>org.springframework.aop.TrueClassFilter

  =>org.springframework.aop.MethodMatcher  匹配當前方法是否需要執行增強邏輯,也就是是否需要執行Advice介面的方法。
  =>org.springframework.aop.TrueMethodMatcher

三:通知器皿(Advisor)
  (1)完成對目標方法的切面增強設計(advice)和關注點的設計(PoinCut)以後,需要一個物件把他們結合起來,完成這個作用的就是(Advisor)
  (2)spring定義的Advisor介面
  =>org.springframework.aop.Advisor
  =>org.springframework.aop.support.DefaultPointcutAdvisor

  (3)Advisor的控制器的介面
  =>org.springframework.aop.framework.adapter.AdvisorAdapter
  =>org.springframework.aop.framework.adapter.AfterReturningAdviceAdapter  目標方法執行完執行該增強的控制器
  =>org.springframework.aop.framework.adapter.MethodBeforeAdviceAdapter  目標方法未執行前執行該增強的控制器
  =>org.springframework.aop.framework.adapter.ThrowsAdviceAdapter   目標方法執行過程丟擲異常執行該增強的控制器

四:springAop的相關
  (1)springAop的核心技術是動態代理。動態代理的技術是jdk的一個特徵。
  (2)springAop的代理物件生成案例
    =>org.springframework.aop.framework.ProxyFactoryBean
    =>org.springframework.aop.framework.ProxyFactory


五:ProxyFactoryBean的工作流程。
(1)實現FactoryBean介面的類,在想IOC容器申請bean的時候,其實返回的是該類執行getObject()方法的返回。
(2)ProxyFactoryBean的getObject()方法返回的是目標物件的代理物件。
  其執行過程
  =>根據配置的interceptorNames的屬性值先初始化代理增強的鏈子.根據interceptorNames從IOC容器中得到增強類的bean,然後判斷其型別,形成DefaultPointcutAdvisor物件。
  =>根據配置的targetName屬性值從IOC容器中得到目標物件的bean,形成一個SingletonTargetSource物件。
  =>將其本身作為一個aop代理物件建立的資料配置類,建立一個動態代理物件,返回給ioc容器申請。
(3)在執行目標物件的方法過程中,會根據執行的方法的物件,從代理鏈子裡找到所有的Advisor物件,然後利用其屬性Pointcut物件獲取ClassFilter, MethodMatcher來判斷當前Advisor是否要執行。如果執行,則加入執行代理鏈子中。以jdk動態代理為例子,是org.springframework.aop.framework.JdkDynamicAopProxy類中invoke(Object proxy, Method method, Object[] args)方法中這句程式碼List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);。該句程式碼中this.advised其實就是ProxyFactoryBean本身。

 

六案例

一:Advice的物件

package com.mobile.thinks.aop.advice;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class LoginBeforeAdvice implements MethodBeforeAdvice{

    @Override
    public void before(Method method, Object[] args, Object target)throws Throwable {
        System.out.println("LoginBeforeAdvice.before()執行方法為==>"+method.getName());
        System.out.println("LoginBeforeAdvice.before()執行引數為==>"+args);
        System.out.println("LoginBeforeAdvice.before()執行的目標為==>"+target.getClass());
    }
    
    

}
View Code

二:目標物件

package com.mobile.thinks.service.impl;

import java.util.Date;

import org.springframework.stereotype.Service;

import com.mobile.thinks.entity.User;
import com.mobile.thinks.service.UserInfoService;

@Service(value="userInfoServiceImpl")
public class UserInfoServiceImpl implements UserInfoService{

    
    @Override
    public User loginByUserNameAndPassWord(String userName, String passWord) {
        User user=new User();
        
        user.setAddress("三門峽");
        user.setAge(28);
        user.setCreateTime(new Date());
        user.setName(userName);
        return user;
    }

    
}
View Code

三:配置檔案

 <!-- 測試ProxyFactoryBean -->
       <!--定義一個advice  -->
       <bean name="loginBeforeAdvice" class="com.mobile.thinks.aop.advice.LoginBeforeAdvice" />
    <!-- 定義FactoryBean -->
    <bean name="userInfoService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 要代理的目標物件,在ioc容器中的名字 -->
        <property name="targetName">
            <value>userInfoServiceImpl</value>
        </property>
        <!-- 要植入增強功能的advice在IOC容器中的名字 -->
        <property name="interceptorNames">
            <list><value>loginBeforeAdvice</value></list>
        </property>
    </bean>
View Code

 

七:spring內部基於該中方式實現動態代理的案例。spring提供的HttpInvoker遠端呼叫.可以閱讀該類getObject方法。實現對Facade介面代理

org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean

相關文章