什么是AOP?
AOP(Aspect Oriented Programming):面向切面編程,與面向對象編程OOP的關鍵單位是類不一樣,它的關鍵單位是切面,它通過提供改變程序結構的方式來補充OOP。通俗點就是說我們可以通過預編譯或者運行時動態(tài)代理在不修改方法源碼的情況下增強方法的功能。
實際開發(fā)中,AOP的出現(xiàn)方便了業(yè)務需求和系統(tǒng)功能之間的解耦和擴展,比如日志、事務、安全、權限等等系統(tǒng)功能,大大減少了重復的代碼,以及維護的復雜,提高了開發(fā)效率。
而AOP的這種解決方式的本質就是代理機制。
準備工作
之前解析Spring源碼或者在實際開發(fā)過程中,相信或多或少都對AOP代理有一些認識,那么在接下來解析源碼前,我們需要先對一些相關基礎作更全面的了解。
基礎概念
切面(Aspect):介紹切面之前,我們先了解切面里面的連接點(JoinPoin),一個連接點就是代表一個類的執(zhí)行方法;而切面就是連接多個類的連接點的一個橫切面(官文稱為跨越多個類的關注點的模塊化模塊化)。通常使用@Aspect注解聲明的就是一個切面。
切點(Pointcut):切面中所有連接點匹配的規(guī)則定義,由多種切點表達式定義,而Spring AOP支持以下j幾種切點表達式,
execution: 匹配方法執(zhí)行的任何連接點。within:匹配指定類型內的方法執(zhí)行的任何連接點。this: 匹配代理實現(xiàn)指定類型接口的任何連接點。target: 匹配目標對象實現(xiàn)指定類型接口的任何連接點。args: 匹配指定類型參數(shù)的方法執(zhí)行的連接點。@target: 匹配目標對象實現(xiàn)指定類型接口的具有指定注解的任何連接點。@args:匹配指定類型參數(shù)的具有指定注解的方法執(zhí)行的連接點。@within: 匹配指定類型內的具有指定注解的方法執(zhí)行的任何連接點。-
@annotation:匹配指定注解的方法執(zhí)行的連接點。其中execution和@annotation在實際開發(fā)中可能更為常用,至于不同表達式的書寫規(guī)則請參考具體的官方文檔說明。
通知:匹配的切點周圍的攔截器方法,Spring中包括一下幾種不同類型的通知,
- 前置通知:方法執(zhí)行的攔截。
- 后置通知:方法執(zhí)行后的攔截,無論正常返回還是異常退出。
- 返回通知:方法正常執(zhí)行完的攔截。
- 環(huán)繞通知:方法執(zhí)行時前后的自定義攔截,手動控制調用的方法。
- 異常通知:方法執(zhí)行時異常退出的攔截。
目標對象:被一個或者多個切面通知的對象,它始終是一個被代理的對象。
使用方式
Spring中有兩種配置使用AOP的方式,分別是:
- 基于XML的配置:配置繁瑣,不同的需求集中配置不符合單一職責原則,無法組合聲明的命名切入點。
- 基于@Aspect的注解:配置簡單,支持更豐富的配置組合,同時具有單元模塊化。這也是開發(fā)中主要的使用方式。
代理機制
Spring中的代理機制分為兩種:
- JDK動態(tài)代理:內置在JDK中,通過攔截和反射來實現(xiàn),被代理的對象必須要實現(xiàn)接口。
- CGLIB動態(tài)代理:一個開源類的定義庫,通過ASM字節(jié)碼生成的方式生成代理類,默認代理沒有實現(xiàn)的接口的對象,不能對final修飾的方法進行代理;Spring中可以通過設置
@EnableAspectJAutoProxy(proxyTargetClass = true)強制使用用CGLIB進行動態(tài)代理。
調用流程
了解完上述一些相關基礎之后,接下來我們將會從源碼來分析AOP的初始化到實際調用的過程。
而完成AOP的初始化其實也是穿插在IOC容器的初始化過程中,前面我們已經了解過IOC容器,包括依賴注入的初始化過程,再來看AOP的相關源碼應該是更加容易下手的,同時這也是對之前內容的補充。
這里我們主要以注解的方式來使用并分析源碼過程。
首先我們寫個簡單的測試類來看下AOP的使用和應用效果,
@Configuration
@EnableAspectJAutoProxy
public class Config {
}
@Component
public class AopA{
public void print(){
System.out.println("AAAAAAAAAAAAAA");
}
}
@Aspect
@Component
public class AspectA {
@Pointcut("execution(* com.test.spring.entity.AopA.*(..))")
public void point(){
}
@Before("point()")
public void before(){
System.out.println("before");
}
@After("point()")
public void after() throws Exception {
System.out.println("after");
}
@Around("point()")
public void around(JoinPoint joinPoint){
System.out.println("aroundBefore");
try {
((ProceedingJoinPoint)joinPoint).proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("aroundAfter");
}
@AfterReturning("point()")
public void afterReturn(){
System.out.println("afterReturn");
}
@AfterThrowing("point()")
public void afterThrow(){
System.out.println("afterThrow");
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext("com.test.spring");
AopA aopA = ac.getBean(AopA.class);
aopA.print();
}
}
運行代碼,控制臺打印如下,
aroundBefore
before
AAAAAAAAAAAAAA
aroundAfter
after
afterReturn
如果方法執(zhí)行過程中拋出異常,則會打印配置的異常通知中的afterThrow。
啟用自動代理
Spring內置了很多豐富且強大的功能,但是并不是每個功能都是默認開啟的,比如AOP自動代理,我們首先得告訴Spring容器去啟用自動代理,這樣它才會掃描、注冊、應用我們配置的相關注解類。而通過注解的方式啟用自動代理也很簡單,就是通過上面測試類中配置的@EnableAspectJAutoProxy注解來啟用。
還是從0到1,我們就從@EnableAspectJAutoProxy注解來入手。
我們先看下這個注解的源碼,
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
其中類上加了一個注解@Import({AspectJAutoProxyRegistrar.class}),而我們知道@Import注解代表AspectJAutoProxyRegistrar對象可以通過配置的@EnableAspectJAutoProxy注解的類去加載,也就是說IOC實例化Config對象的時候也會實例化AspectJAutoProxyRegistrar。
同時這里我們也能看到EnableAspectJAutoProxy具有兩個配置屬性,
- proxyTargetClass:默認false,Spring會根據(jù)被代理對象的實現(xiàn)接口情況去自動選擇JDK或者CGLIB動態(tài)代理機制;設置為true時,代表代理機制強制使用CGLIB動態(tài)代理,但這樣會導致無法對final修飾的方法進行攔截通知,因為它不能被覆寫。
- exposeProxy:是否暴露當前代理對象為
ThreadLocal以便目標可以訪問它。比如方法a()、b()都被攔截通知,默認false時,方法a()中調用b()方法的話,則調用的方法b()不會被攔截通知,如果設置為true時,調用的方法b()也會被攔截通知。
后過頭來,我們繼續(xù)分析下配置完啟動注解之后會發(fā)生什么?以及AspectJAutoProxyRegistrar類的作用。那我們就又要從IOC容器的初始化開始說了,首先我們這里的測試類都是基于Annotation來完成IOC容器的初始化。前面IOC源碼解析中,我們已經知道第一步會調用scan()方法來掃描配置的指定包路徑下的所有Bean對象,并封裝成BeanDefinition對象存放beanDefinitionMap中,之后會調用refresh()方法去載入Bean的配置資源,而這里主要先關注其中的兩個方法,分別是,
//實例化并調用所有已注冊的BeanFactoryPostProcessor的Bean
invokeBeanFactoryPostProcessors(beanFactory);
//注冊BeanPost事件處理器
registerBeanPostProcessors(beanFactory);
我們先看invokeBeanFactoryPostProcessors(),通過注釋大概知道它的作用了,那我們來看看源碼,
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
我們能看出真正的實現(xiàn)是委托PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors()來完成的,
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet<>();
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
一眼望去感覺實現(xiàn)的邏輯相當繁瑣復雜,其實你細看發(fā)現(xiàn)很多代碼處理幾乎是重復的,先獲取postProcessorNames的數(shù)組,然后遍歷調用getBean()實例化并添加到currentRegistryProcessors臨時集合中,接著傳參到invokeBeanFactoryPostProcessors()并調用,最后clear()臨時集合。這里面主要是將實現(xiàn) PriorityOrdered、Ordered 和其余的 BeanDefinitionRegistryPostProcessor 分開處理。首先會實例化并調用實現(xiàn)PriorityOrdered接口ConfigurationClassPostProcessor,它是用來引導處理配置類(配置@Configuration的類),比如配置@Configuration,通常是會默認注冊的,也可以使用任何其他 BeanFactoryPostProcessor 去手動聲明,它會在任何其他 BeanFactoryPostProcessor 執(zhí)行之前注冊了配置類中聲明的Bean定義。我們之前在配置@EnableAspectJAutoProxy的類上也加了@Configuration注解的作用也是因為這個。
其實分析到這里,接下來的流程處理可能就已經柳暗花明了,再往下調用的源碼牽扯的細節(jié)比較多,而且繼續(xù)貼源碼也會顯得比較繁瑣不容易抓住主流程,這里不一一展開了,我會用時序圖來展示后面的流程,

最終就是為了通過AspectJAutoProxyRegistrar的registerBeanDefinitions()方法把對象AnnotationAwareAspectJAutoProxyCreator封裝成BeanDefinition并注冊到容器中去,同時將proxyTargetClass和exposeProxy的屬性值注入進去。
注冊后置處理器
那我們?yōu)槭裁磫觾H僅是通過配置類最終把AnnotationAwareAspectJAutoProxyCreator注冊到容器中去呢?其實我們看下它的類圖結構就知道了,

它實現(xiàn)了BeanPostProcessor接口,我們看下它的源碼,
public interface BeanPostProcessor {
//Bean的初始化前回調
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
//Bean的初始化之后回調
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
而我們知道BeanPostProcessor的作用是:定義了Bean的初始化回調方法,在其實例化、配置和初始化之后實現(xiàn)一些自定義邏輯。你可以理解為Bean對象的攔截器,如果你想擴展Bean的功能或對其修改包裝等,就可以通過實現(xiàn)它去完成。所以AnnotationAwareAspectJAutoProxyCreator的作用就很清楚了,它就是為了在Bean初始化之后對其做一些自定義的處理,至于怎么樣的處理我們后面細講。
但是這里只是將它注冊到容器中去,我們還需要把它實例化并添加到集合List<BeanPostProcessor> beanPostProcessors中去,所以上面的registerBeanPostProcessors()方法就是完成這個事的,
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
同樣真正的實現(xiàn)還是交給PostProcessorRegistrationDelegate去完成的,
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
private static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors){
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
}
我們能看到這里就是將實現(xiàn) PriorityOrdered、Ordered 和其余的 BeanDefinitionRegistryPostProcessor 的BeanPostProcessor分開添加到集合beanPostProcessors中;而我們知道AnnotationAwareAspectJAutoProxyCreator是Ordered的子類,這里我們主要看對orderedPostProcessorNames的處理:
- 首先會遍歷orderedPostProcessorNames集合,拿到AnnotationAwareAspectJAutoProxyCreator;
- 然后調用getBean()方法對其實例化;
- 完成之后調用registerBeanPostProcessors()將AnnotationAwareAspectJAutoProxyCreator添加到BeanPostProcessor的集合中去。
其實到這里才會最終完成自動代理的配置的生效啟用,接下來我們應該也能猜到,將會通過配置的切面類來對匹配規(guī)則的目標Bean在其初始化之后對其做代理的相應處理。
解析@Aspect切面配置
做完上面的這些之后,我們知道IOC容器接下來會調用finishBeanFactoryInitialization()方法對容器中的單例Bean進行預實例化,也就是依賴注入的過程了。
那接下來是怎么解析配置的切面類以及其中定義的切點和通知呢(也就是解析我們配置的AspectA類)?
我們繼續(xù)來分析,我們知道在創(chuàng)建Bean之前,會調用resolveBeforeInstantiation()方法來應用解析Bean配置的實例化前后處理器,
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
也是就會遍歷之前集合添加的BeanPostProcessor并調用父類是InstantiationAwareBeanPostProcessor的子類實現(xiàn)的postProcessBeforeInstantiation()方法,從上面類圖中我們知道,之前添加的AnnotationAwareAspectAutoProxyCreator就是它的子類,而這里真正調用的是AnnotationAwareAspectAutoProxyCreator的父類AbstractAutoProxyCreator的方法實現(xiàn),
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
//存在自定義的TargetSource則創(chuàng)建代理
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
這里先來看下isInfrastructureClass()方法,
protected boolean isInfrastructureClass(Class<?> beanClass) {
boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
Pointcut.class.isAssignableFrom(beanClass) ||
Advisor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass);
if (retVal && logger.isTraceEnabled()) {
logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
}
return retVal;
}
它會判斷當前的Bean是否是不能代理的基礎設施類,比如Advice、PointCut、Advisor等接口的實現(xiàn)類;這里其實就是來篩選我們測試代碼中的切面配置類AspectA,并將它放到Map<Object, Boolean> advisedBeans緩存中。
同時還會調用shouldSkip()方法判斷當前Bean是否應該跳過,這里面就關系著配置@Aspect注解的切面類的配置的提前解析,而這實際委托的是子類AspectJAwareAdvisorAutoProxyCreator實現(xiàn)的,我們往下看,
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor) {
if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
return true;
}
}
}
return super.shouldSkip(beanClass, beanName);
}
這里面實現(xiàn)很簡單,就是調用findCandidateAdvisors()方法獲取通知Advisor的集合,然后遍歷Advisor去檢查配置Pointcurt切點的類的beanName是否和當前Bean的beanName一致,一致則返回true,否則調用父類的shouldSkip()獲取默認的false實現(xiàn)。
我們重點需要看的是findCandidateAdvisors()方法,這里實際調用的是AnnotationAwareAspectJAutoProxyCreator中實現(xiàn),
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
發(fā)現(xiàn)原來是對父類方法的增強,它有個很重要的作用:既保留了父類的獲取xml配置文件定義的通知外,又增加了獲取注解配置的通知。由于我們是通過注解去配置的,我們直接看由aspectJAdvisorsBuilder的buildAspectJAdvisors()方法實現(xiàn)就行,至于findCandidateAdvisors()中的實現(xiàn)感興趣可以自己研究下,你會發(fā)現(xiàn)其實兩種的實現(xiàn)代碼都大同小異,
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<>();
aspectNames = new LinkedList<>();
// 獲取容器中注冊的所有beanName
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
//判斷Bean是否有@Aspect注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//獲取配置的通知方法集合
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
//緩存通知方法
List<Advisor> advisors = new LinkedList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
這個方法的實現(xiàn)流程如下:
- 獲取容器中注冊的所有beanName;
- 遍歷所有beanName,并找到配置@Aspect注解的切面類;
- 解析獲取切面類中配置的通知方法;
- 緩存最后獲取的通知方法。
而其中通知方法的解析是交給ReflectiveAspectJAdvisorFactory的getAdvisors()方法是實現(xiàn)的,
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new LinkedList<>();
// 遍歷配置@Pointcut的方法
for (Method method : getAdvisorMethods(aspectClass)) {
//獲取配置切面的通知方法
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
這里有兩個重要方法:一個是getAdvisorMethods(),獲取切面類中配置@Pointcut的方法,
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new LinkedList<>();
ReflectionUtils.doWithMethods(aspectClass, method -> {
// Exclude pointcuts
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
});
Collections.sort(methods, METHOD_COMPARATOR);
return methods;
}
一個是getAdvisor(),獲取配置切點@Pointcut的幾種通知方法(Before、Around、After、AfterReturning、 AfterThrowing),
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
//封裝切點和通知方法信息
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
//封裝對象
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
//獲取切點表達式
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}
@Nullable
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
Class<?>[] classesToLookFor = new Class<?>[] {
Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
for (Class<?> c : classesToLookFor) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
這幾個方法的主要作用就是將獲取的切點及通知方法信息封裝成InstantiationModelAwarePointcutAdvisorImpl對象,同時這個對象里面定義了不同注解通知的實現(xiàn)策略(感興趣就可以看下實現(xiàn)類的源碼),分別是:
- AspectJMethodBeforeAdvice
- AspectJAfterAdvice
- AspectJAfterReturningAdvice
- AspectJAfterThrowingAdvice
- AspectJAroundAdvice
后面調用相應通知的代理方法時就是由它們去處理實現(xiàn)的。
生成代理對象
完成上面的切面類的解析之后,那下一步肯定就需要根據(jù)定義的切點表達式篩選出目標類,并替換為生成的代理對象。
那我們繼續(xù)往下分析,我們知道在Bean創(chuàng)建完成后,會先進行屬性注入,再調用initializeBean()方法來初始化,而initializeBean()方法中會調用applyBeanPostProcessorsAfterInitialization()方法,來應用之前集合中添加的BeanPostProcessor后置處理器進行初始化處理回調,
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
//遍歷BeanPostProcessor后置處理器
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
能看到這里會遍歷BeanPostProcessor實現(xiàn)類,并調用其實現(xiàn)的postProcessAfterInitialization()方法,而這里我們主要關注的就是之前添加的AnnotationAwareAspectAutoProxyCreator,但是我們看它的源碼,是沒有這個方法的,其實具體的方法實現(xiàn)是在它的父類AbstractAutoProxyCreator中,
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
//獲取緩存的beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
這里先通過earlyProxyReferences來對beanName做緩存判斷,如果你了解過依賴注入中循環(huán)依賴的解決過程,你就知道這段代碼的作用:在對象Bean創(chuàng)建完成后,會先把這個對象的ObjectFactory的放到singletonFactories緩存中來讓有依賴的Bean提前拿到對象的引用,而這個就是ObjectFactory封裝的就是調用getEarlyBeanReference()返回的Bean,這個方法中也會遍歷BeanPostProcessor,并調用getEarlyBeanReference()方法,而它真正調用實現(xiàn)是在AbstractAutoProxyCreator中,
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
this.earlyProxyReferences.add(cacheKey);
}
return wrapIfNecessary(bean, beanName, cacheKey);
}
是不是發(fā)現(xiàn)同樣的都會調用wrapIfNecessary()方法,所以這里緩存判斷的作用就很明顯了,就是為了防止重復調用wrapIfNecessary()方法。而這個方法也是我們重點去了解的,
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
是不是發(fā)現(xiàn)代碼很是熟悉,之前Bean實例化之前就已經提前處理過了并緩存了,我們直接看getAdvicesAndAdvisorsForBean()方法,
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//獲取緩存的通知
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//獲取Bean匹配切點定義的通知
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
這里的作用比較容易理解,就是獲取之前緩存的Advisor的封裝InstantiationModelAwarePointcutAdvisorImpl類的集合,再匹配當前Bean滿足切點定義的通知,結束上層的方法,如果通知為空,則無需要對當前Bean進行代理,反正則會調用createProxy()方法創(chuàng)建當前Bean的代理對象。
我們來看createProxy()方法的實現(xiàn),
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
//判斷配置的proxyTargetClass
if (!proxyFactory.isProxyTargetClass()) {
//確定Bean是否應該用它的目標類而不是它的接口來代理
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
//有接口則添加代理接口,沒有則設置proxyTargetClass為true
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//加入通知攔截器
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
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);
}
}
方法的最后就是通過選擇不同的代理機制來創(chuàng)建代理類,主要就是JDK和CGLIB兩種動態(tài)代理機制,前文也已經簡要介紹過了它們的不同點,至于兩種代理機制更詳細的區(qū)別及實現(xiàn),有機會單獨再寫一篇了。
到此代理對象的生成就結束了。
調用代理方法
等IOC容器初始化完成之后,斷點一下你會發(fā)現(xiàn)所有被代理的對象的引用都是l類似這樣$Proxy27@2699,那么當我們調用其中被通知的方法會是怎樣一個流程呢?
以JDK動態(tài)代理機制為例,我們來探究下,首先會調用JdkDynamicAopProxy的invoke()方法,
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
//判斷是否是eqauls()方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
//判斷是否是hashCode()方法
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
//判斷是否是代理類
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
//判斷是否是Advised接口或者其父接口中定義的方法
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
//獲得目標對象
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
//獲取通知攔截器
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
// 直接反射調用
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
//創(chuàng)建MethodInvocation
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
在方法中,先獲取代理類中的通知攔截器鏈,再調用ReflectiveMethodInvocation的proceed()方法;我們先看下getInterceptorsAndDynamicInterceptionAdvice()方法中是怎么把Advisor轉換成
@Nullable
public Object proceed() throws Throwable {
//執(zhí)行完Interceptor則執(zhí)行joinPoint
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//如果要動態(tài)匹配joinPoint
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
//匹配運行時參數(shù)
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
//調用下一個Interceptor
return proceed();
}
}
else {
//執(zhí)行當前Intercetpor
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
這里的獲取的interceptorOrInterceptionAdvice其實就是之前說的幾種不同注解通知的策略類,分別會調用它們實現(xiàn)的invoke()方法(不同策略的方法實現(xiàn)可以去看看,這里就不貼源碼了),完成配置的通知方法內的自定義實現(xiàn),并且在完成前后會調用invokeJoinpoint()方法,而invokeJoinpoint()方法的本質就是直接通過反射調用被代理類中的目標方法。
到此Spring中完整的AOP實現(xiàn)過程就結束了。
把一件事做到極致就是天分!