回爐Spring--Bean生命周期及AOP


Spring容器:

  在基於Spring的應用中,你的應用對象生存於Spring容器(container)中,Spring容器負責創建對象,裝配它們,配置它們並管理它們的整個生命周期,從生存到死亡。(在這里,可能就是從new()到finalize())。

  容器是Spring框架的核心。Spring容器使用DI(依賴注入)管理構成應用的組件,它會創建相互協作的組件之間的關聯。毫無疑問,這些對象更簡單干凈,更易於理解,更易於重用並且更易於進行單元測試。

1、使用應用上下文

  Spring自帶了多種類型的應用上下文:

  AnnotationConfigApplicationContext: 從一個或多個基於Java的配置類中加載Spring應用上下文。

  AnnotationConfigWebApplicationContext: 從一個或多個基於Java的配置類中加載Spring Web應用上下文。

  ClassPathXmlApplicationContext: 從類路徑下的一個或多個XML配置文件中加載上下文定義, 把應用上下文的定義文件作為類資源。

  FileSystemXmlapplicationcontext: 從文件系統下的一個或多個XML配置文件中加載上下文定義。

  XmlWebApplicationContext: 從Web應用下的一個或多個XML配置文件中加載上下文定義。

無論是從哪里裝載應用上下文,將bean加載到bean工廠的過程都是類似的。

如果你想從Java配置中加載應用上下文, 那么可以使用AnnotationConfig-ApplicationContext:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationContextConfig.class);

在這里沒有指定加載Spring應用上下文所需的XML文件, AnnotationConfig-ApplicationContext通過一個配置類加載bean。

應用上下文准備就緒之后, 我們就可以調用上下文的getBean()方法從Spring容器中獲取bean。

Spring注解驅動開發

使用Java配置類代替XML配置文件來裝配bean:

package com.yang.config;

import com.yang.domain.Person;
import com.yang.factory.StudentFactoryBean;
import com.yang.service.TestService;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;

/**
 * Spring 基於Java類注解形式的配置
 *
 * @Configuration 使Spring容器知道這是一個配置類
 * @ComponentScan 啟用組件掃描,默認掃描本文件所在的包及其子包下聲明了@Component注解的類,並在Spring容器中為其創建一個bean
 * value屬性指定要掃描的包
 * includeFilters 指定掃描的時候只需要包含哪些組件
 * excludeFilters 指定掃描的時候按照什么規則排除那些組件
 * 如:excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)排除Controller注解的類
* @PropertySource 使用@PropertySource讀取外部配置文件中的k/v保存到運行的環境變量Environment中;加載完外部的配置文件以后使用${key}取出配
*  置文件的值。也可以用Spring容器獲取Environment變量,然后getProperty獲取到配置的value
*  ConfigurableEnvironment environment = context.getEnvironment();
*  String name = environment.getProperty("name"); *
*/ @Import(TestService.class) @Configuration @ComponentScan(value = "com.yang")
@PropertySource(value = {"classpath:/applicationContext.properties"})
public class ApplicationContextConfig { /** * 向Spring容器中注冊一個bean,默認作用域是單例的 * 類型為方法的返回值 * bean的id為方法名,也可以使用@Bean的name屬性指定bean的名稱。
   * JavaConfig如何實現注入依賴?
   *   1、直接引用創建依賴bean的方法,使用的是帶參構造器。但是這種引用並不會創建多個依賴bean的對象,因為Spring將會攔截對它的調用,並確保直接返回
   *    該方法所創建的bean,而不是每次都對其進行實際的調用。 *   2、將依賴的bean類型當成@Bean所在方法的一個參數。當Spring調用@Bean注解所在方法創建bean的時候,會自動裝配一個參數類型bean到方法之中,然后
   *    方法體就可以按照合適的方式來使用它。這種方式不會像方式1那樣要求將依賴bean的聲明和當前bean在同一個配置類之中,甚至不要求依賴bean必須在JavaConfig
   *    類中聲明。
   *      疑問,若有多個同一類型的依賴bean,Spring怎么選擇裝配?
   *      答案:先參數類型,后參數名稱。源碼在DefaultListableBeanFactory#doResolveDependency:1213
   * * @Scope bean的作用域,取值范圍: * ConfigurableBeanFactory#SCOPE_PROTOTYPE singleton 單例,默認,Spring容器啟動就會創建對象並放在容器中,以后每次獲取都去map中取 * ConfigurableBeanFactory#SCOPE_SINGLETON prototype 原型/多例,Spring容器啟動時並不會去創建對象,每次獲取的時候都回去創建一個新的對象 * org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST request 同一個請求創建一個對象 * org.springframework.web.context.WebApplicationContext#SCOPE_SESSION session 同一個session創建一個對象

      問題?Spring為啥把bean默認設計成單例?
        優勢:為了提高性能
          1、減少創建新實例的消耗
          2、減少JVM垃圾回收
          3、可以快速獲取到bean
        劣勢:不能做到線程安全,bean如果是有狀態的話在並發環境下線程不安全 * * @Lazy 即懶加載,針對單實例作用域的bean,默認值為true,即Spring容器啟動的時候不創建,調用的時候才去創建 * * @Conditional 按照一定的條件進行判斷,滿足條件給容器中注冊bean,若用在配置類上,則此配置類上的所有的bean都滿足條件在會去Spring容器中 * 去注冊。使用場景如只在linux系統中才創建bean * Class<? extends Condition>[] value(); 接收一個實現Condition接口的類的class對象,需要自定義類實現Condition接口在matches方法中實 * 現具體判斷邏輯,返回true代表符合條件 *
*/ @Lazy(value = false) @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) @Bean public Person person() { return new Person("yangyongjie"); } /** public class StudentFactoryBean implements FactoryBean<Student> { public Student getObject() throws Exception { return new Student(); } public Class<?> getObjectType() { return Student.class; } public boolean isSingleton() { return false;//false 多例 true 單例 } } 實際是將Student對象注冊到Spring容器中 */ @Bean public StudentFactoryBean studentFactoryBean(){ return new StudentFactoryBean(); }
}
 向Spring容器中注冊組件的四種方式:
   1、包掃描+組件標注注解(@Component、@Controller、@Service、@Repository)   2、@Bean,適合導入第三方包里面的組件 3、@Import,快速給容器中導入一個組件   1、@Import(要導入的組件的class對象),容器中就會自動注冊這個bean,名稱是全類名(com.yang.service.TestService)    2、@Import(ImportSelector.class),在ImportSelector中返回需要導入的組件的全類名數組   3、@Import(ImportBeanDefinitionRegistrar.class)手動注冊bean到容器中(在ImportBeanDefinitionRegistrar中使用BeanDefinitionRegistry的registerBeanDefinition方法手動注冊)

技巧:BeanDefinitionRegistry:接口,提供往Spring容器中注冊bean,移除bean,獲取容器中所有注冊了的bean和判斷Spring容器中是否注冊了某個bean
4、使用Spring提供的 FactoryBean(工廠Bean),與普通bean不同的是,普通bean是調用其無參構造器去創建對象然后注冊到容器中,FactoryBean是調用其   T getObject()方法,將返回的對象注冊到Spring容器中 1、默認獲取的工廠bean調用getObject創建的對象 2、注冊到容器中工廠bean的id為 “&+bean名稱”,如&studentFactoryBean

問題:BeanFactory和FactoryBean的區別
BeanFactory是IOC容器的核心接口,Spring使用BeanFactory來實例化、配置和管理bean,采用延遲加載的方式來注入bean,只有在getBean的時候才去加載創建bean
FactoryBean是創建bean的工廠,通過自定義類實現FactoryBean<T>接口,實現其getObject()方法創建bean對象,在配置文件中使用FactoryBean創建bean對象

BeanFactory和ApplicationContext的區別
ApplicationContext是完整的IOC容器,其由BeanFactory派生而來,具有BeanFactory的所有功能,可以通過配置實現,且額外提供了messageSource,資源訪問,aop和web應用
,加載多種應用上下文。並可在啟動的時候一次性創建所有需要的單實例bean

Spring容器中Bean的生命周期
  bean創建--初始化--銷毀
   容器管理bean的生命周期,
    若是單例的bean,在Spring容器的啟動后先創建對象,再初始化,容器關閉的時候銷毀bean。
    若是多實例的bean,Spring容器在每次獲取的時候才去創建對象,然后初始化,但是Spring容器關閉時並不會去銷毀bean,需要手動去銷毀。

bean初始化和銷毀四種方式:
  
1、指定在bean中自定義初始化和銷毀方法,通過@Bean注解指定initMethod和destroyMethod

     @Bean(initMethod = "customInit",destroyMethod = "customDestory")
  2、指定在bean中自定義初始化和銷毀方法,然后使用javax提供的注解
            @PostConstruct標注在bean的初始化方法上,將在bean創建並屬性賦值完成,調用此方法
@PreDestroy標注在bean的銷毀方法上,將在容器銷毀對象之前調用

  3、通過使Bean實現InitializingBean和DisposableBean接口,在重寫的afterPropertiesSet和destroy方法實現初始化和銷毀邏輯

  4、bean的后置處理器,BeanPostProcessor接口,針對全局的bean,自定義bean實現了BeanPostProcessor接口,那么容器中其他所有bean(只針對單例的bean)在初始化方法之前之前
    都會調用postProcessBeforeInitialization,在初始化方法執行之后都會調用postProcessAfterInitialization
      postProcessBeforeInitialization 在初始化之前調用
postProcessAfterInitialization 在初始化之后調用

如果四種都寫了,那么執行順序為:

  constructor  創建bean實例
  postProcessBeforeInitialization  BeanPostProcessor的初始化前置方法
  PostConstruct  javax注解定義的初始化方法
  afterPropertiesSet  實現InitializingBean接口的初始化方法
  customInit  @Bean注解上自定義的初始化方法
  postProcessAfterInitialization  BeanPostProcessor的初始化后方法
  PreDestroy  javax注解定義的銷毀方法
  destroy  實現DisposableBean接口的銷毀方法
  customDestory  @Bean注解上自定義的銷毀方法

初始化和銷毀的執行順序都是  BeanPostProcessor-->javax提供的注解-->InitializingBean/DisposableBean-->@Bean custom

 BeanPostProcessor原理
  populateBean(beanName, mbd, instanceWrapper);給bean進行屬性賦值
  initializeBean 
  {
    applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    invokeInitMethods(beanName, wrappedBean, mbd);執行自定義初始化
    applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

      遍歷得到容器中所有的BeanPostProcessor;挨個執行beforeInitialization,一但返回null,跳出for循環,不會執行后面的BeanPostProcessor.postProcessorsBeforeInitialization

  }

  Spring底層對BeanPostProcessor的使用:

    1、其實現類ApplicationContextAwareProcessor可對實現了ApplicationContextAware接口的bean(對bean類型作了判斷,只針對部分bean)注入容器ApplicationContext依賴對象,代碼如下:

        if (System.getSecurityManager() != null &&
                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

 

    2、其實現類InitDestroyAnnotationBeanPostProcessor,對bean中標注了@PostContruct和@PreDestory注解的方法進行調用執行

    3、其實現類AutowiredAnnotationBeanPostProcessor,在對象創建完成以后,對所有標注了@Autowired注解的屬性進行注入值

   
@Value
  使用@Value注解為屬性賦值
  1、可以直接寫基本數值
  2、可以寫SPEL表達式#{}
  3、可以寫${},取出在配置文件中配置的,容器啟動放到環境變量Environment中的值

自動裝配
  創建容器中對象協作關系的行為叫做裝配,是DI的核心,即為容器中各個組件的依賴關系賦值
  1、@AutoWired,自動注入
    1)默認按照類型byType去容器中找對應的組件,然后注入;applicationContext.getBean(xxx.class)
    2)如果找到多個相同類型的組件,再將屬性的名稱作為組件的id去容器中查找
    3)@Qualifier("xxx"):執行需要裝配的組件的id,而不是使用屬性名
    4)自動裝配默認一定要將屬性賦值好,沒有就會報錯,可以使用@AutoWired(required=false),允許不注入
    5)@Primary:用在依賴的類上,讓Spring進行自動裝配的時候,默認首選裝配它  2、@Resource
    和@AutoWired一樣實現自動裝配功能,默認是按照屬性名稱ByName進行裝配的,按名稱沒有找到則再按類型進行裝配,如果指定了name或者type則按照名稱和類型進行裝配,沒有找到則報錯
  3、Inject
    需要導入javax.inject的包,和Autowired的功能一樣。沒有required=false的功能
  
4、自定義組件想要使用Spring容器底層的一些組件(ApplicationContext,BeanFactory,xxx);
    自定義組件實現xxxAware;在創建對象的時候,會調用接口規定的方法注入相關組件;Aware;
    把Spring底層一些組件注入到自定義的Bean中;
    xxxAware:功能使用xxxProcessor,是通過后置處理器來實現的。
    ApplicationContextAware==》ApplicationContextAwareProcessor;

  技巧:自定義Bean實現xxxAware接口,重寫其中的方法可為我們的自定義Bean注入Spring底層的組件xxx,原理是通過xxxProcessor,一個實現了后置處理器
    BeanPostProcessor的類通過在Bean初始化前后做的事情來實現的。如下面所示的實現ApplicationContextAware 接口,為我們的Bean注入了ApplicationContext 對象

 
@Component
public class Child implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
  @Autowired:Spring定義的; @Resource、@Inject都是java規范  
  AutowiredAnnotationBeanPostProcessor:解析完成自動裝配功能; 

   @Autowired:構造器,參數,方法,屬性;都是從容器中獲取參數組件的值
    1)、[標注在方法位置]:@Bean+方法參數;參數從容器中獲取;默認不寫@Autowired效果是一樣的;都能自動裝配
    2)、[標在構造器上]:如果組件只有一個有參構造器,這個有參構造器的@Autowired可以省略,參數位置的組件還是可以自動從容器中獲取
    3)、放在參數位置:

高級裝配

  @Profile(value = "env"):指定組件在哪個環境的情況下才能被注冊到容器中。

    1、加了環境標識的bean,只有在這個環境被激活的時候才能注冊到容器中,默認激活環境是default

    2、若標注在配置類上,則只有在執行的環境激活的時候,整個配置類里面的所有配置才生效

    3、沒有標注環境標識@Profile注解的bean在任何環境下都會注冊的

  如何激活Profile環境:

  1、使用命令行動態參數:在虛擬機參數位置加載-Dspring.profiles.active=test

  2、代碼的方式激活某個環境變量,需要在啟動Spring容器的時候使用無參構造不傳配置文件的參數

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        // 設置需要激活的環境
        context.getEnvironment().setActiveProfiles("pre");
        // 注冊主配置類
        context.register(ApplicationContextConfig.class);
        // 啟動刷新容器
        context.refresh();

 

AOP

實現一個AOP的步驟:

  1、將業務邏輯組件和切面類都注入到Spring容器中,標注使Spring知道哪個是界面類,@Aspect(曾犯錯,在切面類上沒有標注@Component注解)

  2、在切面類上的每一個通知方法上都標注通知注解(如@Around),並在注解中指明切入點表達式

  3、開啟基於注解的aop模式,在配置類上加上注解@EnableAspectJAutoProxy

@AfterReturning注解的returning可將方法的返回值映射到參數上

@AfterReturning(value = "pointCut()", returning = "result")
    public void afterReturning(Object result) throws Throwable {}

@AfterThrowing(value="pointCut()",throwing="exception")的throwing將異常信息映射到參數上

獲取切入點方法名:joinPoint.getSignature().getName()

獲取方法入參:joinPoint.getArgs()

    @Before("pointCut()")
    // 方法若有多個參數,JoinPoint一定要放在第一位
    public void before(JoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
    }

 @EnableAspectJAutoProxy注解做了什么?

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy 

  往容器中導入了AspectJAutoProxyRegistrar,利用AspectJAutoProxyRegistrar自定義的往容器中注冊了name為internalAutoProxyCreator,class

為AnnotationAwareAspectJAutoProxyCreator的bean。

  技巧:如果看到了Enable開頭的注解,就看這個注解有沒有往容器中注冊一些組件,如果注冊組件了,這些組件的功能是什么,如果具體功能搞明白了,那么這個注解的原理就清楚了。

  那么既然@EnableAspectJAutoProxy往Spring容器中注入了AnnotationAwareAspectJAutoProxyCreator這個bean(從名字看是:注解裝配切面代理創造器),

那就看一下這個bean的功能是什么,源碼走起:

class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator
  class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator
    abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator
      abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
        interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor
          interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor

其中:class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanClassLoaderAware, AopInfrastructureBean

看到其祖先類實現了InstantiationAwareBeanPostProcessor 接口,而此接口又實現了BeanPostProcessor接口,而這個接口我們知道叫做后置處理器,后置處理器

的功能就是在bean初始化的前后做一些工作。

抽象父類AbstractAutoProxyCreator 又實現了BeanFactoryAware,可以往代碼中注入BeanFactory。

那么先重點看與setBeanFactory以及與后置處理器相關的邏輯,通過源碼發現AbstractAutoProxyCreator有setBeanFactory()以及后置處理器相關的邏輯。而在

AbstractAutoProxyCreator的子抽象類AbstractAdvisorAutoProxyCreator又重寫了setBeanFactory()方法

    public void setBeanFactory(BeanFactory beanFactory) {
        super.setBeanFactory(beanFactory);
        if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
            throw new IllegalArgumentException("AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
        } else {
            this.initBeanFactory((ConfigurableListableBeanFactory)beanFactory);
        }
    }

由於其子類AnnotationAwareAspectJAutoProxyCreator 重寫了initBeanFactory方法,所以最終調用的是AnnotationAwareAspectJAutoProxyCreator 中的initBeanFactory方法中的邏輯:

  protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        super.initBeanFactory(beanFactory);
        if (this.aspectJAdvisorFactory == null) {
            this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
        }

        this.aspectJAdvisorsBuilder = new AnnotationAwareAspectJAutoProxyCreator.BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
    }

 

斷點看AOP的整個執行流程:

1、new AnnotationConfigApplicationContext(AopConfig.class); 創建Spring容器,接下來看其構造器邏輯

2、先注冊配置類,然后調用refresh()方法刷新容器,接下來看refresh()的邏輯

3、invokeBeanFactoryPostProcessors(beanFactory);實例化並調用所有注冊的BeanFactoryPostProcessor

4、registerBeanPostProcessors(beanFactory); 注冊bean的后置處理器來攔截bean的創建

  1):先獲取ioc容器中已經定義了的需要創建對象的所有BeanPostProcessor {String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);}

  2):給容器中添加了額外的BeanPostProcessor{beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));}

  3):遍歷BeanPostProcessor按照是否實現PriorityOrdered接口進行分組,若實現了,根據其name獲取其對象(beanFactory.getBean(ppName, BeanPostProcessor.class);)

  將其放進priorityOrderedPostProcessors集合,若其又實現了MergedBeanDefinitionPostProcessor,將其再放進internalPostProcessors集合;若其實現了Ordered接口,

  將其bean name放入orderedPostProcessorNames集合;否則將其name放進nonOrderedPostProcessorNames集合

  4):優先注冊實現了PriorityOrdered接口的BeanPostProcessor,再注冊實現了Ordered接口的BeanPostProcessor,最后注冊其他的BeanPostProcessor

  5):注冊其實就是步驟3)中的根據其name獲取BeanPostProcessor對象{BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);},實際上就是

  創建BeanPostProcessor對象然后將其保存在Spring容器中。以創建name為internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】為例,看

  一下創建過程:

    (1):創建bean的實例(createBeanInstance)

    (2):給bean的各種屬性賦值(populateBean)

    (3):初始化bean(initializeBean)

      (1):invokeAwareMethods()判斷bean是不是實現了xxxAware接口,如果實現了就調用相關的setXxx方法給bean的屬性賦值

      (2):wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);應用bean的后置處理器的初始化前置方法,獲取所有的后置處理器,

        遍歷之后順序應用。for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {result = beanProcessor.postProcessBeforeInitialization(result, beanName);...

      (3):invokeInitMethods(beanName, wrappedBean, mbd); 執行初始化方法,如果實現了InitializingBean,執行afterPropertiesSet,再執行自定義的初始化方法(如

        果在@Bean注解指定了initMethod的話)

      (4):wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);應用bean的后置處理器的初始化后置方法,獲取所有的后置處理器,

        遍歷之后順序應用。for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {result = beanProcessor.postProcessAfterInitialization(result, beanName);

  6):由於AnnotationAwareAspectJAutoProxyCreator實現了 BeanFactoryAware接口,所以在invokeAwareMethods()方法中,回到了上面說的調用其抽象父類

   AbstractAdvisorAutoProxyCreator重寫的setBeanFactory()方法。然后走到了AnnotationAwareAspectJAutoProxyCreator 的initBeanFactory()方法,至此,

   BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)創建成功

  7):將所有的BeanPostProcessor注冊到BeanFactory中 (registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);-->beanFactory.addBeanPostProcessor(postProcessor);)

  以上就是創建和注冊AnnotationAwareAspectJAutoProxyCreator的過程。

  接下來看其作為一個BeanPostProcessor如何影響bean的創建過程的:

5、finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作,創建剩下的單實例bean,為什么說是剩下的呢?因為BeanPostProcessors類型的bean在步驟4已經創建

  完成了

  1):preInstantiateSingletons()-->遍歷獲取容器中所有的beanDefinitionNames,遍歷依此創建對象getBean(beanName); 在DefaultListableBeanFactory類中

  2):getBean(beanName)-->doGetBean()-->getSingleton(beanName) ,在創建bean之前先嘗試獲取單實例Bean的實例,為什么呢?因為只要創建好的bean就會被緩存起來

    (1)先檢查JVM緩存中是否有對應的實例,因為在創建單實例bean的時候會存在依賴注入的情況,為了避免循環依賴,Spring在創建bean

    的過程中,若發現有依賴bean,則嘗試去創建依賴的bean,因此Spring將每一個正在創建的bean的beanName放在一個“當前創建

    bean池”中,bean在創建過程中,BeanName將一直存在這個池中。當前創建bean池:

    private final Set<String> singletonsCurrentlyInCreation =Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));

    如果當前線程創建bean池有,則嘗試從緩存中加載bean

    /** Cache of early singleton objects: bean name --> bean instance */
    private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

    (2)如果緩存中加載不成功,則再次嘗試從singletonFactories中獲取提前曝光的ObjectFactory,如果根據beanName找到了ObjectFactory,則從ObjectFactory中獲取bean

    實例,然后將其放在earlySingletonObjects 緩存中,再將其ObjectFactory從singletonFactories中移除。

    /** Cache of singleton factories: bean name --> ObjectFactory */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

    因為Spring為了避免循環依賴,在Spring中創建bean的原則是不等bean創建完就會將創建bean的ObjectFactory提早曝光加入到緩存中,一旦下一個bean創建時候需要依賴

    上一個bean則直接使用ObjectFactory去獲取依賴bean的實例。

  3):createBean(); 創建bean

    (1):Object bean=resolveBeforeInstantiation(beanName, mbdToUse); 參數:RootBeanDefinition mbdToUse,bean的定義信息。方法的作用是:給BeanPostProcessor

    一個機會返回一個代理對象就不用創建其對象了。如果可以,直接返回代理對象,如果不能,則繼續執行doCreateBean(beanName, mbdToUse, args);,其實現為:

    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); 這個方法的邏輯是:先拿到所有的后置處理器然后遍歷,如果其中一個后置處理器實現了

      InstantiationAwareBeanPostProcessor接口,則執行這個后置處理器的postProcessBeforeInstantiation方法,如果返回了bean對象,則執行applyBeanPostProcessorsAfterInitialization

    並返回bean實例,結束bean的創建,不走下面的doCreateBean。
    if (bean != null) {
      bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
    }

    注意:InstantiationAwareBeanPostProcessor雖繼承了BeanPostProcessor,但其定義了postProcessBeforeInstantiation和postProcessAfterInstantiation方法,與BeanPostProcessor

    的postProcessBeforeInitialization和postProcessAfterInitialization方法不同,BeanPostProcessor的兩個方法是在bean實例創建完成之后的初始化前后調用的,而

    InstantiationAwareBeanPostProcessor的兩個方法是在創建bean實例之前嘗試返回代理對象的。

    這也是AnnotationAwareAspectJAutoProxyCreator的功能,在所有的bean創建之前會有一個攔截,嘗試返回其代理對象。

    (2):doCreateBean,真正的創建bean的實例,即4.5的流程

 

AnnotationAwareAspectJAutoProxyCreator做了什么事情?

1、每一個bean創建之前,都會調用postProcessBeforeInstantiation();其處理邏輯是:

  1):判斷當前bean是否在advisedBean(保存了所有增強過的bean)中

  2): 判斷當前bean是否是 基礎類型的Advice、Pointcut、Advisor、AopInfrastructureBean或者是否是切面(是否有@Aspect注解)

  3):或者是否需要跳過

    (1):獲取候選的增強器(切面里面的增強方法)[List<Advisor> candidateAdvisors = findCandidateAdvisors();]

      (斷點來看我們的每一個封裝的通知方法的增強器類型是InstantiationModelAwarePointcutAdvisor);遍歷然后判斷每一個增強器是否是AspectJPointcutAdvisor類型的,

      如果是,返回true,否則返回flase

2、postProcessAfterInstantiation和postProcessBeforeInitialization一個返回true,一個返回bean對象本身,什么都沒做

3、postProcessAfterInitialization方法:創建完對象並初始化后,調用它。其邏輯是:

  判斷當前bean是否已經代理過,若沒有則:return wrapIfNecessary(bean, beanName, cacheKey);這個方法的作用是,封裝bean如果必要的話。

  1):Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);找到所有能應用到當前bean的增強方法

    (1):獲取配置的所有的切面增強方法

    (2):找到所有的增強方法中能應用到當前bean方法中的

    (3):獲取到能在當前bean使用的增強方法的集合,並按照一定規則排序

    (4):如果能在當前bean使用的增強方法的集合不為空,則轉為數組返回,否則返回null

  2):如果返回的數組不為空,則需要代理

    (1):將bean的name作為key,值為true,放在advisedBeans(所有增強過的bean的ConcurrentHashMap)中

    (2):創建代理對象

      step1:如果能在當前bean使用的增強方法

      step2:遍歷將其添加到proxyFactory中

      step3: DefaultAopProxyFactory中創建代理對象,Spring自動決定

       JdkDynamicAopProxy(AdvisedSupport config)

      ObjenesisCglibAopProxy(AdvisedSupport config)

    (3):將bean作為key,代理對象的class對象作為value,保存到private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<Object, Class<?>>(16);中

    (4):返回代理對象

    (5):以后在容器中獲取到的就是這個組件的代理對象,執行目標方法的時候,代理對象就會執行增強方法的流程

  3)否則不需要代理,將bean的name作為key,值為false,放在advisedBeans中

   

執行目標對象Target中的切入點方法,即執行被增強的方法的流程:

 從容器中獲取的對象是代理對象,即容器中保存了組件的代理對象(cglib增強后的對象),這個對象里面保存了詳細的信息(比如要應用的切面中的增強方法,也叫增強器,目標對象等)

1、CglibAopProxy.intercept();攔截目標方法的執行

2、根據ProxyFactory對象獲取將要執行的目標方法攔截器鏈

  List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

    1):List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); 集合長度為一個默認的 ExposeInvocationInterceptor.ADVISOR和其他被執行方法的增強器

    2):遍歷所有的增強器,將其轉為MethodInterceptor  【MethodInterceptor[] interceptors = registry.getInterceptors(advisor);】

                        如果是MethodInterceptor,直接放入List<MethodInterceptor>集合中

         如果不是,使用AdvisorAdapter將增強器轉為MethodInterceptor,然后再放入List<MethodInterceptor>集合中

         最后將集合轉為數組返回

3、如果沒有攔截器鏈,則直接執行目標方法(攔截器鏈,每一個通知方法又被包裝為方法攔截器,利用MethodInterceptor機制)

4、如果有攔截器鏈,把需要執行的目標對象,目標方法,攔截器等信息作為參數創建一個CglibMethodInvocation對象並調用其proceed()方法

  retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); 

  CglibMethodInvocation對象:

  

  攔截器列表:

  

5、攔截器的觸發過程

  1):如果沒有攔截器執行目標方法,或者攔截器的索引和攔截器數組-1大小一樣(即執行到了最后一個攔截器),則執行目標方法

  2):鏈式獲取每一個攔截器,攔截器執行invoke方法,每一個攔截器等待下一個攔截器執行完成返回后再去執行(類似於遞歸調用),

    如上面攔截器的調用順序是 Expose-->AfterReturning-->Around-->Before,然后前面的等待后面的返回再執行,最后實際執行順

    序是Before-->Around-->AfterReturning-->Expose

    攔截器鏈的機制,保證通知方法與目標方法的執行順序。

  

AOP總結

  1、@EnableAspectJAutoProxy  開啟AOP功能

  2、@EnableAspectJAutoProxy  會給容器中注冊一個組件 AnnotationAwareApectJAutoProxyCreator

  3、AnnotationAwareApectJAutoProxyCreator是一個后置處理器

  4、容器的創建流程

    1):registerBeanPostProcessors(beanFactory);  注冊后置處理器,創建AnnotationAwareApectJAutoProxyCreator對象

    2):finishBeanFactoryInitialization(beanFactory);  初始化剩下的單實例bean

      (1):創建業務邏輯自檢和切面組件

      (2):AnnotationAwareApectJAutoProxyCreator  攔截組件的創建過程

      (3): 組件創建完成之后,作為后置處理器的AnnotationAwareApectJAutoProxyCreator在postProcessAfterInitialization

        方法中判斷組件是否需要增強,如果需要則 將需要應用到目標對象的切面中的通知方法,包裝成增強器Advisor,然后

        給業務邏輯組件創建一個代理對象。

  5、執行目標方法

    1):代理對象來執行目標方法

    2):CglibAopProxy.intercept();攔截目標方法的執行

      (1):得到目標方法執行的攔截器鏈

      (2):利用攔截器的鏈式機制,依次進入每一個攔截器進行執行

      (3):實際執行順序:

      正常執行:前置通知-->目標方法-->后置通知-->返回通知

      出現異常:前置通知-->目標方法-->后置通知-->異常通知

      

     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM