Spring IOC和AOP
Spring提供了很多輕量級應用開發實踐的工具集合,這些工具集以介面、抽象類、或工具類的形式存在於Spring中。通過使用這些工具集,可以實現應用程式與各種開源技術及框架間的友好整合。比如有關jdbc封裝的資料訪問工具Spring JDBC,有關編寫單元測試的spring test包以及spring-mock,有關訪問動態指令碼語言的Spring Script,另外還有傳送郵件的工具Spring Mail、日程及任務處理工具Spring scheduling等。 可以這麼說,大多數企業級應用開發中經常涉及到的一些通用的問題,都可以通過Spring提供的一些實用工具包輕鬆解決
依賴注入的三種方式:(1)介面注入(2)Construct注入(3)Setter注入
控制反轉(IoC)與依賴注入(DI)是同一個概念,引入IOC的目的:(1)脫開、降低類之間的耦合;(2)倡導面向介面程式設計、實施依賴倒換原則; (3)提高系統可插入、可測試、可修改等特性。 具體做法:(1)將bean之間的依賴關係儘可能地抓換為關聯關係; (2)將對具體類的關聯儘可能地轉換為對Java interface的關聯,而不是與具體的服務物件相關聯; (3)Bean例項具體關聯相關Java interface的哪個實現類的例項,在配置資訊的元資料中描述; (4)由IoC元件(或稱容器)根據配置資訊,例項化具體bean類、將bean之間的依賴關係注入進來。
org.springframework.beans及org.springframework.context包是Spring IoC容器的基礎。BeanFactory提供的高階配置機制,使得管理任何性質的物件成為可能。ApplicationContext是BeanFactory的擴充套件,功能得到了進一步增強,比如更易與Spring AOP整合、訊息資源處理(國際化處理)、事件傳遞及各種不同應用層的context實現(如針對web應用的WebApplicationContext)。 簡而言之,BeanFactory提供了配製框架及基本功能,而ApplicationContext則增加了更多支援企業核心內容的功能。ApplicationContext完全由BeanFactory擴充套件而來,因而BeanFactory所具備的能力和行為也適用於ApplicationContext。
IoC容器負責容納bean,並對bean進行管理。在Spring中,BeanFactory是IoC容器的核心介面。它的職責包括:例項化、定位、配置應用程式中的物件及建立這些物件間的依賴。Spring為我們提供了許多易用的BeanFactory實現,XmlBeanFactory就是最常用的一個。該實現將以XML方式描述組成應用的物件以及物件間的依賴關係。XmlBeanFactory類將持有此XML配置元資料,並用它來構建一個完全可配置的系統或應用。
實現化容器:
- Resource resource = new FileSystemResource("beans.xml");
- BeanFactory factory = new XmlBeanFactory(resource);
- ... 或...
- ClassPathResource resource = new ClassPathResource("beans.xml");
- BeanFactory factory = new XmlBeanFactory(resource);
- ... 或...
- ApplicationContext context = new ClassPathXmlApplicationContext(
- new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
- // of course, an ApplicationContext is just a BeanFactory
- BeanFactory factory = (BeanFactory) context;
將XML配置檔案分拆成多個部分是非常有用的。為了載入多個XML檔案生成一個ApplicationContext例項,可以將檔案路徑作為字串陣列傳給ApplicationContext構造器。而bean factory將通過呼叫bean defintion reader從多個檔案中讀取bean定義。
通常情況下,Spring團隊傾向於上述做法,因為這樣各個配置並不會查覺到它們與其他配置檔案的組合。另外一種方法是使用一個或多個的<import/>元素來從另外一個或多個檔案載入bean定義。所有的<import/>元素必須放在<bean/>元素之前以完成bean定義的匯入。 讓我們看個例子:
<beans><import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/> <bean id="bean2" class="..."/> </beans>
在上面的例子中,我們從3個外部檔案:services.xml、messageSource.xml及themeSource.xml來載入bean定義。這裡採用的都是相對路徑,因此,此例中的services.xml一定要與匯入檔案放在同一目錄或類路徑,而messageSource.xml和themeSource.xml的檔案位置必須放在匯入檔案所在目錄下的resources目錄中。正如你所看到的那樣,開頭的斜槓‘/’實際上可忽略。因此不用斜槓‘/’可能會更好一點。
根據Spring XML配置檔案的Schema(或DTD),被匯入檔案必須是完全有效的XML bean定義檔案,且根節點必須為<beans/> 元素。
BeanFactory和FactoryBean的區別,簡而言之,BeanFactory是載入的容器,載入一切的BEAN,而FactoryBean用於建立代理類
===============================================================上面已講到
BeanFactory它的職責包括:例項化、定位、配置應用程式中的物件及建立這些物件間的依賴。
FactoryBean(通常情況下,bean無須自己實現工廠模式,Spring容器擔任工廠角色;但少數情況下,容器中的bean本身就是工廠,其作用是產生其它bean例項),作用是產生其他bean例項。通常情況下,這種bean沒有什麼特別的要求,僅需要提供一個工廠方法,該方法用來返回其他bean例項。由工廠bean產生的其他bean例項,不再由Spring容器產生,因此與普通bean的配置不同,不再需要提供class元素。
ProxyFactoryBean用於建立代理(根據Advisor生成的Bean,也就是TargetBean的代理)
我們的Advisor,PointCut等等,其最終目的都是為了建立這個代理。
===============================================================下面將講到
AOP全名Aspect-Oriented Programming,中文直譯為面向切面(方面)程式設計,當前已經成為一種比較成熟的程式設計思想,可以用來很好的解決應用系統中分佈於各個模組的交叉關注點問題。在輕量級的J2EE中應用開發中,使用AOP來靈活處理一些具有橫切性質的系統級服務,如事務處理、安全檢查、快取、物件池管理等,已經成為一種非常適用的解決方案。 AOP中比較重要的概念有:Aspect、JoinPoint、PonitCut、Advice、Introduction、Weave、Target Object、Proxy Object等
引介(Introduction)是指給一個現有類新增方法或欄位屬性,引介還可以在不改變現有類程式碼的情況下,讓現有的Java類實現新的介面,或者為其指定一個父類從而實現多重繼承。相對於增強(Advice)可以動態改變程式的功能或流程來說,引介(Introduction)則用來改變一個類的靜態結構。比如我們可以讓一個現有為實現java.lang.Cloneable介面,從而可以通過clone()方法複製這個類的例項。
攔截器是用來實現對連線點進行攔截,從而在連線點前或後加入自定義的切面模組功能。在大多數JAVA的AOP框架實現中,都是使用攔截器來實現欄位訪問及方法呼叫的攔截(interception)。所用作用於同一個連線點的多個攔截器組成一個聯結器鏈(interceptor chain),連結上的每個攔截器通常會呼叫下一個攔截器。Spring AOP及JBoos AOP實現都是採用攔截器來實現的。
面向物件程式設計(OOP)解決問題的重點在於對具體領域模型的抽象,而面向切面程式設計(AOP)解決問題的關鍵則在於對關注點的抽象。也就是說,系統中對於一些需要分散在多個不相關的模組中解決的共同問題,則交由AOP來解決;AOP能夠使用一種更好的方式來解決OOP不能很好解決的橫切關注點問題以及相關的設計難題來實現鬆散耦合。因此,面向方面程式設計 (AOP) 提供另外一種關於程式結構的思維完善了OOP,是OOP的一種擴充套件技術,彌補補了OOP的不足。
AOP概念詳解:注意以下例項<aop:開頭的AspectJ的概念,Spring沒有分的這麼細。
— 方面(Aspect):一個關注點的模組化,這個關注點實現可能另外橫切多個物件。事務管理是一個很好的橫切關注點例子。方面用Spring的Advisor或攔截器實現, 然後可以通過@Aspect標註或在applictionContext.xml中進行配置:
<aop:aspect id="fourAdviceAspect" ref="fourAdviceBean" order="2">
— 連線點(Joinpoint):程式執行過程中的行為,如方法的呼叫或特定的異常被丟擲,在程式碼上有JoinPoint類和ProceedingJoinPoint類,如下所示,可以通過JoinPoint獲取很多引數,JoinPoint一般用在Advice實現方法中作為引數傳入,ProceedingJoinPoint用於實現圍繞Advice的引數傳入。 通過下面JoinPoint的介面可以看出通過JoinPoint可以得到代理物件和Target物件。
- package org.aspectj.lang;
- import org.aspectj.lang.reflect.SourceLocation;
- public interface JoinPoint {
- String toString(); //連線點所在位置的相關資訊
- String toShortString(); //連線點所在位置的簡短相關資訊
- String toLongString(); //連線點所在位置的全部相關資訊
- Object getThis(); //返回AOP代理物件
- Object getTarget(); //返回目標物件
- Object[] getArgs(); //返回被通知方法引數列表
- Signature getSignature(); //返回當前連線點簽名
- SourceLocation getSourceLocation();//返回連線點方法所在類檔案中的位置
- String getKind(); //連線點型別
- StaticPart getStaticPart(); //返回連線點靜態部分
- }
- public interface ProceedingJoinPoint extends JoinPoint {
- public Object proceed() throws Throwable;
- public Object proceed(Object[] args) throws Throwable;
- }
— 切入點(Pointcut):指定一個Adivce將被引發的一系列連線點的集合。AOP框架必須允許開發者指定切入點,例如,使用正則表示式。
xml中配置:
<aop:pointcut id="myPointcut" expression="execution(* com.wicresoft.app.service.impl.*.*(..))" method="release" />
或使用Annoation :@pointcut("execution * transfer(..)")並用一個返回值為void,方法體為空的方法來命名切入點如: private void anyOldTransfer(){}
之後就可以在Advice中引用,如: @AfterReturning(pointcut="anyOldTransfer()", returning="reVal")
- package org.springframework.aop;
- public interface Pointcut {
- ClassFilter getClassFilter();
- MethodMatcher getMethodMatcher();
- Pointcut TRUE = TruePointcut.INSTANCE;
- }
- package org.springframework.aop;
- public interface ClassFilter {
- boolean matches(Class<?> clazz);//如果clazz與我們關注的現象相符時返回true,負責返回false
- ClassFilter TRUE = TrueClassFilter.INSTANCE;//靜態引數 如果型別對於要撲捉的Pointcut來說無所謂,可將此引數傳遞給Pointcut
- }
- package org.springframework.aop;
- public interface MethodMatcher {
- boolean matches(Method method, Class<?> targetClass);
- /**
- * 是否對引數值敏感
- * 如果為false表明匹配時不需要判斷引數值(引數值不敏感),稱之為StaticMethodMatcher,這時只有
- * matches(Method method, Class<?> targetClass); 被執行,執行結果可以快取已提高效率。
- * 如果為true表明匹配時需要判斷引數值(引數值敏感),稱之為DynamicMethodMatcher,這時先執行
- * matches(Method method, Class<?> targetClass);如果返回true,然後再執行
- * boolean matches(Method method, Class<?> targetClass, Object[] args);已做進一步判斷
- *
- */
- boolean isRuntime();
- boolean matches(Method method, Class<?> targetClass, Object[] args);
- MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
- }
關於PointCut中使用的execution的說明:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
modifiers-pattern:方法的操作許可權
ret-type-pattern:返回值
declaring-type-pattern:方法所在的包
name-pattern:方法名
parm-pattern:引數名
throws-pattern:異常
記憶法則就是Java定義一個方法時的樣子:public boolean produceValue(int oo) throws Exception, 只要在方法名前加上包名就可以了。
其中,除ret-type-pattern和name-pattern之外,其他都是可選的。上例中,execution(* com.spring.service.*.*(..))表示com.spring.service包下,返回值為任意型別;方法名任意;引數不作限制的所有方法。
常見的PointCut結構圖:
— 通知(Advice):在特定的連線點,AOP框架執行的動作。各種型別的通知包括“around”、“before”和“throws”通知。通知型別將在下面討論。許多AOP框架包括Spring都是以攔截器做通知模型,維護一個“圍繞”連線點的攔截器鏈。Advice中必須用到PointCut
在xml中配置,配置中的method為Aspect實現類中的方法名,使用pointcut自定義或pointcut-ref進行引用已有pointcut
<aop:before pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="authority" />
<aop:after pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="release" />
<aop:after-returning pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="log" />
<aop:around pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="processTx" />
<aop:after-throwing pointcut-ref="myPointcut" method="doRecovertyActions" throwing="ex" />
或使用Annoation:
@Before("execution(* com.wicresoft.app.service.impl.*.*(..))")
@AfterReturning(returning="rvt", pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))")
@AfterThrowing(throwing="ex", pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))")
@After("execution(* com.wicresoft.app.service.impl.*.*(..))")
@Around("execution(* com.wicresoft.app.service.impl.*.*(..))")
注意
- AfterReturning 增強處理處理只有在目標方法成功完成後才會被織入。
- After 增強處理不管目標方法如何結束(儲存成功完成和遇到異常中止兩種情況),它都會被織入。
使用方法攔截器的around通知,需實現介面MethodInterceptor:
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
invoke()方法的MethodInvocation 引數暴露將被呼叫的方法、目標連線點、AOP代理和傳遞給被呼叫方法的引數。 invoke()方法應該返回呼叫的結果:連線點的返回值。
一個簡單的MethodInterceptor實現看起來如下:
- public class DebugInterceptor implements MethodInterceptor {
- public Object invoke(MethodInvocation invocation) throws Throwable {
- System.out.println("Before: invocation=[" + invocation + "]");
- Object rval = invocation.proceed();
- System.out.println("Invocation returned");
- return rval;
- }
- }
注意MethodInvocation的proceed()方法的呼叫。這個呼叫會應用到目標連線點的攔截器鏈中的每一個攔截器。大部分攔截器會呼叫這個方法,並返回它的返回值。但是, 一個MethodInterceptor,和任何around通知一樣,可以返回不同的值或者丟擲一個異常,而不呼叫proceed方法。但是,沒有好的原因你要這麼做。
Before通知:需實現MethodBeforeAdvice介面
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method m, Object[] args, Object target) throws Throwable;
}
Throw通知,需實現ThrowsAdvice介面
After Returning通知須直線AfterReturningAdvice介面
public interface AfterReturningAdvice extends Advice {
void afterReturning(Object returnValue, Method m, Object[] args, Object target)
throws Throwable;
}
— 引入(Introduction):新增方法或欄位到被通知的類,引入新的介面到任何被通知的物件。例如,你可以使用一個引入使任何物件實現IsModified介面,來簡化快取。使用introduction要有三個步驟(1)宣告新介面(2)建立自己的IntrouductionInterceptor通過Implements IntroductionInterceptor或extends DelegatingIntroductionInterceptor 並同時implements(1)中宣告的介面 (3)將新介面和自定義的IntroductionInterceptor配置到DefaultIntroductionAdvisor中,然後將前三者配置到ProxyFactoryBean中。
- public interface IOtherBean {
- public void doOther();
- }
- public class SomeBeanIntroductionInterceptor implements IOtherBean, IntroductionInterceptor {
- public void doOther() {
- System.out.println("doOther!");
- }
- public Object invoke(MethodInvocation invocation) throws Throwable {
- //判斷呼叫的方法是否為指定類中的方法
- if ( implementsInterface(invocation.getMethod().getDeclaringClass()) ) {
- return invocation.getMethod().invoke(this, invocation.getArguments());
- }
- return invocation.proceed();
- }
- /**
- * 判斷clazz是否為給定介面IOtherBean的實現
- */
- public boolean implementsInterface(Class clazz) {
- return clazz.isAssignableFrom(IOtherBean.class);
- }
- }
- <!-- 目標物件 -->
- <bean id="someBeanTarget" class="aop.spring.introduction.SomeBeanImpl" />
- <!-- 通知 -->
- <bean id="someBeanAdvice" class="aop.spring.introduction.SomeBeanIntroductionInterceptor" />
- <!-- 通知者,只能以構造器方法注入-->
- <bean id="introductionAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor">
- <constructor-arg ref="someBeanAdvice" />
- <constructor-arg value="aop.spring.introduction.IOtherBean" />
- </bean>
- <!-- 代理 (將我們的切面織入到目標物件)-->
- <bean id="someBeanProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <!-- 若目標物件實現了代理介面,則可以提供代理介面的配置 -->
- <property name="proxyInterfaces" value="aop.spring.introduction.ISomeBean" />
- <!-- 配置目標物件 -->
- <property name="target" ref="someBeanTarget" />
- <!-- 配置切面 -->
- <property name="interceptorNames">
- <list>
- <value>introductionAdvisor</value>
- </list>
- </property>
- </bean>
— 攔截器(Advisor )常用的有PointCutAdvisor和IntroudtionAdvisor。前者Advisor有PointCut和Advice組成,滿足Poincut(指定了哪些方法需要增強),則執行相應的Advice(定義了增強的功能),後者由Introduction構成。PointCutAdvisor主要是根據PointCut中制定的Target Objects的方法在呼叫(前,後,around,throws, after-return等)時引入新的Aspect中的methods, 而IntroductionAdvisor主要是引入新的介面到Targets物件中。
- public interface PointcutAdvisor {
- Pointcut getPointcut();
- Advice getAdvice();
- }
1、 PointcutAdvisor: Advice和Pointcut,預設實現為DefaultPointcutAdvisor, 還有NameMatchMethodPointcutAdvisor,RegexpMethodPointcutAdvisor等。
其中NameMacthMethodPointCutAdvisor、RegexpMethodPointCutAdvisor 可以對比常用的PointCut類有NameMatchedMethodPointCut和JdkRegexMethodPointCut。 前者需要注入mappedName和advice屬性,後者需要注入pattern和advice屬性。其中mappedName和pattern是直接配置的值,而advice需要自己實現具體的advice,可見實現advisor的時候,不需要實現PointCut,一般PointCut只需要配置就好了,不需要具體實現類 mappedName指明瞭要攔截的方法名,pattern按照正則表示式的方法指明瞭要攔截的方法名,advice定義了一個增強(需要自己實 現MethodBeforeAdvice、 MethodAfterAdvice、ThrowsAdvice、MethodInterceptor介面之 一)。然後在ProxyFactoryBean的攔截器(interceptorNames)中注入這個PointCutAdvisor即可,如上面這個ProxyFactoryBean是一個靜態代理,只能代理一個類給加上AOP,那麼這個靜態代理需要注入有目標物件,目標物件的介面,和interceptorsNames
2、 IntroductionAdvisor :預設實現為DefaultIntroductionAdvisor,這個主要與Introduction有關,可以參考上面的例子
— 目標物件(Target Object):包含連線點的物件,也被稱作被通知或被代理物件。
— AOP代理(AOP Proxy):AOP框架建立的物件,包含通知。在Spring中,AOP代理可以是JDK動態代理或CGLIB代理。如ProxyFactory,ProxyFactoryBean, 下面會進行詳細說明
— 編織(Weaving):組裝方面來建立一個被通知物件。這可以在編譯時完成(例如使用AspectJ編譯器),也可以在執行時完成。Spring和其他純Java AOP框架一樣,在執行時完成織入。將Aspect加入到程式程式碼的過程,對於Spring AOP,由ProxyFactory或者ProxyFactoryBean負責織入動作。
通過ProxyFactory可以將對符合條件的類呼叫時新增上Aspect。
或者 可使用XML宣告式 ProxyFactoryBean:需要設定 target,interceptorNames(可以是Advice或者Advisor,注意順序, 對介面代理需設定proxyInterfaces
注意:一個ProxyFactoryBean只能指定一個代理目標,不是很方便,這就產生了自動代理。通過自動代理,可以實現自動為多個目標Bean實現AOP代理、避免客戶端直接訪問目標Bean(即getBean返回的都是Bean的代理物件)。spring的自動代理是通過BeanPostProcessor實現的,容器載入xml配置後會修改bean為代理Bean,而id不變。
ApplicationContext可以直接檢測到定義在容器中的BeanPostProcessor,BeanFactory需要手動新增。 有2種常用的BeanPostProcessor: 1.BeanNameAutoProxyCreator 故名思議,BeanName需要注入的兩個屬性有BeanNames和interceptorNames
- <bean id="loginBeforeAdvisor" .../>
- <bean id="loginThrowsAdvisor" .../>
- <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
- <!-- 注入目標Bean -->
- <property name="beanNames" value="*Service">
- </property>
- <property name="interceptorNames">
- <list>
- <value>loginBeforeAdvisor</value>
- <value>loginThrowsAdvisor</value>
- </list>
- </property>
- </bean>
2.DefaultAdvisorAutoProxyCreator: DefaultAdvisorAutoProxyCreator和BeanNameAutoProxyCreator不同的是,前者只和Advisor 匹配, 該類實現了BeanPostProcessor介面。當應用上下文讀入所有的Bean的配置資訊後,該類將掃描上下文,尋找所有的Advisor,他將這些Advisor應用到所有符合切入點的Bean中。所以下面的xml中沒有繫結也無需繫結DefaultAdvisorAutoProxyCreator與Advisor的關係。
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
- <beans>
- <bean id="kwikEMartTarget" class="demo.ApuKwikEMart"></bean>
- <bean id="performanceThresholdInterceptor" class="demo.advice.PerformanceThresholdInterceptor">
- <constructor-arg>
- <value>5000</value>
- </constructor-arg>
- </bean>
- <!-- 使用RegexpMethodPointcutAdvisor來匹配切入點完成個一個Advisor; -->
- <bean id="regexpFilterPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
- <property name="pattern">
- <!-- 匹配的名字為方法名-->
- <value>.*buy.*</value>
- </property>
- <property name="advice">
- <ref bean="performanceThresholdInterceptor"/>
- </property>
- </bean>
- <bean id="defaultAdvisorAutoProxyCreator"
- class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
- </beans>
在使用Aonnotation的時候,需要進行在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"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/beans/spring-aop-3.0.xsd">
- <!-- 啟動對@AspectJ註解的支援 -->
- <aop:aspectj-autoproxy/>
- </beans>
綜上,Spring下AOP的配置與實現,BeanNameAutoProxyCreator,DefaultAdvisorAutoProxyCreator已經部分簡化了AOP配置,然而還是很繁瑣: 首先要編寫xxxAdvice類(需要自己實現MethodBeforeAdvice、MethodAfterAdvice、 ThrowsAdvice、MethodInterceptor介面之一),然後還要在xml中配置Advisor,還要在Advisor中注入 Advice,最後還要將Advisor加入ProxyFactoryBean、BeanNameAutoProxyCreator或者 DefaultAdvisorAutoProxyCreator中
。
實際上AOP不止Spring進行了實現,還有AspectJ,後者對AOP中的概念實現比較徹底,可以看上面,而Spring中對AOP的方方面面進行簡化,拿上面定義的regexpFilterPointcutAdvisor是一種Advisor包含了PointCut和Advice,而此處的PointCut就是pattern屬性的值了,沒有特定的PointCut Bean定義,而advice定義了Bean。而其他概念Aspect, JoinPoint都融匯於Advice的實現中即Advisor(MethodBeforeAdvice等和MethodIntector介面的實現類)或IntroductionInterceptor了。