Spring基礎
- @Configuration
標註在類上,相當於Spring XML配置文件中的<beans>標籤,用來配置Spring容器上下文。例如:初始化數據源實例。 - @ComponentScan
標註在類上,主要負責掃描配置組件並將其注入IOC,與@Configuration一起使用。
通過其includeFilters屬性指定特定註解生效,excludeFilters指定排除註解,使其失效。
@ComponentScan(value = "com.lmx", includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)}, useDefaultFilters = false)
- @Scope
指定容器中實例的作用域,取值於singleton、prototype、request1、session2,默認singleton。 - @Lazy
指定容器中實例是否啓用延遲加載,默認取值爲false,不用則不適用@Lazy標註。 - @Condition
Spring4.0 增加的條件註解,通過該註解可實現Bean實例的選擇性注入。例如,針對Win7系統轉配Win7配置的業務。 - @PropertySource
加載指定的屬性文件。例如,@PropertySource(value= {“classpath:config/jdbc-dev.properties”},ignoreResourceNotFound=false,encoding=“UTF-8”,name=“jdbc-dev.properties”) - @Import
用來整合所有在@Configuration註解中定義的bean配置,相當於將單個配置實例導入到IOC中。 - @ImportResource
加載指定XML配置文件,可以與@Import實現註解和XML的混合配置。 - BeanDefinition API
Spring Bean實例的原型,存儲IOC實例的相關信息,例如作用域、是否開啓延遲加載、實例名稱等。 - ImportSelector API
是spring中導入外部配置的核心接口,在SpringBoot的自動化配置和@EnableXXX(功能性註解)都有它的存在。 - ImportBeanDefinitionRegistrar API
該接口可實現Bean實例的手動/動態註冊。例如,Feign的啓動註解@EnableFeignClients中通過@Import導入了FeignClientsRegistrar,其集成自ImportBeanDefinitionRegistrar,通過此API完成默認配置的加載工作。
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
registerDefaultConfiguration(metadata, registry);
registerFeignClients(metadata, registry);
}
`
-
BeanFactory
對象工廠/IOC容器。Spring中所有對象實例都交由BeanFactory進行管理。 -
FactoryBean
一個Bean實例,但又不同於普通實例,是能夠生產並修飾Bean實例的工廠實例,是工廠模式和裝飾器模式結合的產物。 -
BeanFactoryAware API
實現了BeanFactoryAware接口的bean,可以直接通過beanfactory來訪問spring的容器。
環境搭建
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.11</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.66</version>
</dependency>
<!-- mysql 依賴 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
·
@Data
public class UserEntity {
private Integer userId;
private String userName;
public UserEntity(Integer userId, String userName) {
this.userId = userId;
this.userName = userName;
}
}
@Configuration
@ComponentScan(value = {"com.lming"})
public class MySpringConfig {
@Bean
public UserEntity userEntity() {
return new UserEntity(1, "zhangsan");
}
}
public class TestMain {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);
System.out.println("------->>>>打印所有IOC中的實例");
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
UserEntity userEntity = context.getBean("userEntity", UserEntity.class);
System.out.println("獲取到實例:" + userEntity);
}
}
IOC源碼分析
Spring將IOC的加載分爲三個階段。初始化階段加載基礎環境,註冊階段注入一個或多個註解類到IOC,刷新上下文階段進行掃包刷新配置信息,若IOC容器已存在,則銷燬註冊階段創建的IOC容器,重新創建容器,完成容器初始化工作。
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
// 1.初始化階段
this();
// 2.註冊階段
register(annotatedClasses);
// 3.刷新上下文階段
refresh();
}
初始化階段
初始化階段完成讀取器和掃描器的加載。
public AnnotationConfigApplicationContext() {
// 註解實例讀取器
this.reader = new AnnotatedBeanDefinitionReader(this);
// 類掃描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
`
註解讀取器(AnnotatedBeanDefinitionReader)
調用鏈
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
// getOrCreateEnvironment獲取運行環境信息
this(registry, getOrCreateEnvironment(registry));
}
——> public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
——> public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
registerAnnotationConfigProcessors()中將註解處理器加載到IOC中,比如@Configuration、@Autowired、BeanFactory的驅動處理器等。
// 省略部分代碼……
// 初始化2 - 比如@Configuration註解的驅動處理器
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 初始化3 - 比如@Autowired註解的驅動處理器
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 省略部分代碼……
類掃描器(ClassPathBeanDefinitionScanner)
類掃描器初始化工作包括三部分,注入過濾器、環境變量、加載類資源。
調用鏈
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
this(registry, true);
}
——> public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
// getOrCreateEnvironment獲取運行環境信息
this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}
——> public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment) {
this(registry, useDefaultFilters, environment,
(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
}
——> public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
// 初始化4.1 - 註冊默認過濾器(@Service @Controller @Repostory @Component全靠這裏,includeFilters指定裝載那些實例)
registerDefaultFilters();
}
// 初始化4.2 - 裝載系統環境配置,比如os.name,系統版本win7/10等
setEnvironment(environment);
// 初始化4.3 - 裝載資源加載器,主要用來在程序內加載一些外部資源文件
setResourceLoader(resourceLoader);
}
在registerDefaultFilters()中會註冊一個默認的過濾器,與@ComponentScan註解配置includeFilters息息相關。
protected void registerDefaultFilters() {
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
初始化階段總結
初始階段完成後,我們將得到一個具備處理關鍵註解、獲取系統環境信息、可加載外部資源的應用程序上下文對象AnnotationConfigApplicationContext。
結構圖
註冊階段
註冊階段通過初始化的註解讀取器向上下文中注入一個或多個配置類實例,配置類優先於其他實例加載,使後續規則得以應用。例如:MySpringConfig。
調用鏈
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
this.reader.register(componentClasses);
}
——> public void register(Class<?>... componentClasses) {
// 依次解析配置
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}
——> public void registerBean(Class<?> beanClass) {
doRegisterBean(beanClass, null, null, null);
}
// 核心註冊邏輯
——> <T> void doRegisterBean(Class<T> beanClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
// 註冊1 - 解析@Configuration,將註解裝換爲實例,註冊到IOC
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// 註冊1.1 - 執行Bean過濾規則@Conditional
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
// 註冊1.2 - 指定創建 bean 實例的回調方法,此時爲 null
abd.setInstanceSupplier(instanceSupplier);
// 解析bean作用域(單例或者原型),如果有@Scope註解,則解析@Scope,沒有則默認爲singleton
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
// 作用域寫回BeanDefinition數據結構, abd中缺損的情況下爲空,將默認值singleton重新賦值到abd
abd.setScope(scopeMetadata.getScopeName());
// 生成bean配置類beanName
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 註冊1.3 - 通用註解解析到abd結構中,主要是處理Lazy, primary DependsOn, Role ,Description這五個註解
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
// 如果配置@Primary註解,則設置當前Bean爲自動裝配autowire時首選bean
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
// 設置當前bean爲延遲加載
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
// 其他註解,則添加到abd結構中
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
// 註冊1.4 - 根據Bean名稱和BeanDefinition創建一個Holder,Holder是二者的映射對象
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
——> public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// 獲取主選項的實例名稱.
String beanName = definitionHolder.getBeanName();
// 註冊1.5 - 將BeanDefinition注入到IOC容器(所有實例都將被封裝爲BeanDefinition)
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// (如果有)註冊次級選項bean名稱的別名。
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
IDEA Ctrl+ALT+B查看BeanDefinitionRegistry API的DefaultListableBeanFactory的註冊實現:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// 省略部分代碼……
if (existingDefinition != null) {
// 省略部分代碼……
// 註冊1.6 - Spring使用ConcurrentHashMap保存BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 省略部分代碼……
}
}
查看beanDefinitionMap,是ConcurrentHashMap的BeanDefinition集合,故我們可以得知IOC默認是採用ConcurrentHashMap存儲實例。
註冊階段總結
- 重點完成了bean配置類本身的解析和註冊,主要是一些註解信息;
- Bean實例作用域、延遲加載、主從等註解處理;
- 最後使用ConcurrentHashMap存儲實例。
結構圖
`
刷新上下文階段
刷新上下文階段是對整個Spring框架是至關重要的,同時也非常的複雜。這裏只專注於聯合研究IOC與AOP,因此省略其他部分的內容。
- 掃包並執行BeanFactory後置處理器(invokeBeanFactoryPostProcessors)
- 註冊攔截Bean的相關處理器(registerBeanPostProcessors)
- 實例化所有剩餘的單例Bean(非延遲初始化)(finishBeanFactoryInitialization)
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 刷新前的預處理
prepareRefresh();
// 獲取刷新後的內部Bean工廠
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// BeanFactory的預準備工作
prepareBeanFactory(beanFactory);
try {
// BeanFactory準備工作完成後,可以做一些後置處理工作,空方法,用於在容器的子類中擴展
postProcessBeanFactory(beanFactory);
// 刷新上下文1.1.1 - 執行BeanFactory後置處理器 ,在IOC初始化後實例構造方法之前執行
invokeBeanFactoryPostProcessors(beanFactory);
// 刷新上下文1.2.1 - 註冊攔截Bean的相關處理器,這是實現AOP的核心
registerBeanPostProcessors(beanFactory);
// 初始化MessageSource組件(做國際化功能;消息綁定,消息解析)
initMessageSource();
// 初始化事件派發器
initApplicationEventMulticaster();
// 空方法,可以用於子類實現在容器刷新時自定義邏輯
onRefresh();
// 註冊時間監聽器,將所有項目裏面的ApplicationListener註冊到容器中來
registerListeners();
// 刷新上下文1.3.1 - 實例化所有剩餘的單例Bean(非延遲初始化)。
finishBeanFactoryInitialization(beanFactory);
// 完成BeanFactory的初始化創建工作,IOC容器就創建完成;
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - "
"cancelling refresh attempt: " + ex);
}
// 銷燬已創建的單例以避免資源懸空。
destroyBeans();
// 重置'active' 旗幟.
cancelRefresh(ex);
throw ex;
}
finally {
// 重置Spring核心中的常見自省緩存,因爲我們 //可能不再需要單例bean的元數據...
resetCommonCaches();
}
}
}
刷新上下文階段 - 調用BeanFactory後置處理器
作用:允許我們在工廠裏所有的bean被加載進來後但是還沒初始化前,對所有bean的屬性進行修改也可以add屬性值。
執行時機:在IOC初始化後實例構造方法之前執行。
環境搭建
在MySpringConfig類上添加:@Import({MyBeanFactoryPostProcessor.class})
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
System.out.println("BeanFactory後置處理器,篩選所有Bean實例中名稱爲“payEntity”的實例,並將其amount改爲500");
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println("當前迭代實例------>>>" + beanDefinitionName);
if (beanDefinitionName.equals("payEntity")) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
System.out.println("開始修改,對象原屬性值爲:" + JSON.toJSONString(beanDefinition.getPropertyValues()));
beanDefinition.getPropertyValues().add("amount", "500");
System.out.println("修改後,對象原屬性值爲:" + JSON.toJSONString(beanDefinition.getPropertyValues()));
return;
}
}
}
}
源碼分析
我將BeanFactory後處理器分爲兩步進行分析,註冊以及執行。
註冊(Spring 掃包)
我們回到刷新上下文階段 invokeBeanFactoryPostProcessors(beanFactory)階段,官方給定的解釋是:
Instantiate and invoke all registered BeanFactoryPostProcessor beans,respecting explicit order if given.
翻譯過來就是:實例化並調用所有已註冊的BeanFactoryPostProcessor,(如果給定的話)遵循顯式順序。也就是說註冊和執行皆由invokeBeanFactoryPostProcessors完成,它是至關重要的。
調用鏈
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// 省略部分代碼……
}
// invokeBeanFactoryPostProcessors代碼比較長,這裏只貼關鍵代碼
——> public static void invokeBeanFactoryPostProcessors(
// 省略部分代碼…… 這部分代碼主要是對BeanDefinitionRegistryPostProcessor進行排序
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// 1、首先,調用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();
// 2、然後,調用Ordered接口實現,我們寫的MyBeanFactoryPostProcessor不在這兩個層次;
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();
// 3、最後, 調用其他BeanDefinitionRegistryPostProcessors.
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();
}
// 省略BeanFactory後置處理器執行部分代碼……
// 我們重點關注invokeBeanDefinitionRegistryPostProcessors的調用
}
——> private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
IDEA快捷鍵Ctrl+Alt+B查看postProcessBeanDefinitionRegistry實現,默認只有ConfigurationClassPostProcessor。我們繼續查看其postProcessBeanDefinitionRegistry的調用鏈,解析註冊過程:
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
// 省略部分日誌代碼……
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
// 這裏是Spring 掃包的入口
——> public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
// checkConfigurationClassCandidate檢索IOC中所有的@Configuration註解類,到這一步爲止IOC中只有一個@Configuration註解類他就是我們自定義的MySpringConfig,在註冊階段注入IOC。
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 如果未找到@Configuration類,則立即返回
if (configCandidates.isEmpty()) {
return;
}
// 省略部分代碼……主要是排序
// 接下來我們看Spring是如何掃包的,如何解析Configuration類的
do {
parser.parse(candidates);
parser.validate();
// 省略部分重織代碼,即將candidates重置後重新織入,我們主要關注parse中掃包注入過程
}
while (!candidates.isEmpty());
// 省略部分注入代碼……
}
——> public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<>();
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
// MySpringConfig是註解式的所以走這裏
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
// 省略部分catch代碼……
// 處理延遲導入的ImportSelectors
processDeferredImportSelectors();
}
——> protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
——> protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
// 執行@Condition選擇性注入的條件
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// 獲取到@Configuration註解類,也就是MySpringConfig
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
// 省略部分非必要性代碼……
// 遞歸處理配置類及其超類層次結構。實際上是在檢測註解或是超類的一些格式/規範問題。
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
// Spring 掃描的核心
——> protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// 首先遞歸處理任何成員(嵌套)類
processMemberClasses(configClass, sourceClass);
// 解析@PropertySource註解,@PropertySource用來加載指定的屬性文件。
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
// 省略@PropertySource解析代碼……
}
// 解析 @ComponentScan 註解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// 通過初始化階段的類路徑掃描器掃描@ComponentScan標註範圍內的所有類(ClassPathBeanDefinitionScanner)
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// 檢查掃描的定義集是否有其他配置類,並在需要時遞歸解析
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
if (ConfigurationClassUtils.checkConfigurationClassCandidate(
holder.getBeanDefinition(), this.metadataReaderFactory)) {
parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
}
}
}
}
// 處理所有的 @Import 註解,我們自定的BeanFactory後置處理器就是在這裏被註冊的!!
processImports(configClass, sourceClass, getImports(sourceClass), true);
// 處理所有@ImportResource 註解,@ImportResource主要用來裝配XML配置文件
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// 處理單個 @Bean 註解方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// 處理接口的默認方法
processInterfaces(configClass, sourceClass);
// (如果有)處理超類
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// 到超類,返回其註釋元數據並遞歸
return sourceClass.getSuperClass();
}
}
// 沒有超類->處理完成
return null;
}
// @Import的解析是比較複雜的,Spring單獨拿了出來
——> private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
// 省略非核心代碼……
for (SourceClass candidate : importCandidates) {
// 候選類是ImportSelector實現類,走這裏進行註冊
// 例如@EnableTransactionManagement註解,就是ImportSelector的實現
if (candidate.isAssignable(ImportSelector.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
// 候選類是ImportBeanDefinitionRegistrar實現類,從這裏進行註冊
// 例如,@EnableAspectJAutoProxy的關鍵類AspectJAutoProxyRegistrar就是這種實現,@EnableTransactionManagemen也有它的身影。
// BeanFactory後置處理器,並非上訴兩種實現類型
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
// BeanFactory直接實現BeanFactoryPostProcessor接口,既沒有實現ImpostSelector也沒有實現ImportBeanDefinitionRegistrar,則直接按照@Configuration方式解析
else {
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
// BeanFactory後置處理器走processConfigurationClass遞歸完成解析工作
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
// 省略異常處理代碼……
}
到這裏所有IOC的註冊/掃描已經完成,也就是說這是容器中包括了項目中所需要的用到的大部分實例,當然@Lazy延遲加載的除外。
現在我們來總結一下注冊過程:
- Spring掃描在第三階段刷新上下文中invokeBeanFactoryPostProcessors完成,其會執行所有BeanDefinitionRegistryPostProcessor的實現,Spring默註冊階段默認會注入;ConfigurationClassPostProcessor;
- 掃描前,獲取到由第二階段註冊中注入的啓動配置文件(MySringConfig)並解析文件標註的註解;
- 首先,獲取配置類的所有超類,若具有內部類,則需先遞歸解析;
- 第一步,解析所有@PropertySource註解,其作用是加載指定的屬性文件
- 第二步,解析所有@ComponentScan註解3,通過初始化階段的ClassPathBeanDefinitionScanner類路徑掃描器完成遞歸掃描;
- 第三步,處理所有@Import註解,分爲三種類型:
-
ImportSelector實現型,例如@EnableTransactionManagement註解,就是ImportSelector的實現;
-
ImportBeanDefinitionRegistrar手動注入型,例如,@EnableAspectJAutoProxy的關鍵類AspectJAutoProxyRegistrar就是這種實現,@EnableTransactionManagement中也有它的身影;
-
其他類型Import,都按照@Configuration進行遞歸解析。 BeanFactory後置處理器既沒有實現ImpostSelector也沒有實現ImportBeanDefinitionRegistrar,則直接按照@Configuration方式解析。
-
- 第四步,處理所有@ImportResource註解,解析XML配置;
- 第五步,處理@Bean註解方法,注入Bean實例;
- 第六步,處理接口上的默認方法,注入默認實現方法;
- 最後,如果存在超類,則遞歸解析超類 ,否則結束掃描。
結構圖
執行BeanFactory後置處理器
現在我們回到註冊/掃描階段我們忽略掉的那部分後置處理器執行代碼。
調用鏈
// 以下代碼來自,PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors
// 省略註冊/掃描階段代碼……
// 現在,調用到目前爲止已處理的所有處理器的postProcessBeanFactory回調。
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// 調用向上下文實例註冊的工廠處理器。
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 不要在這裏初始化FactoryBeans:我們需要保留所有常規bean //未初始化,以使Bean工廠後處理器對其應用!!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// 對BeanFactory後置處理器排序
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// 跳過-已在上述第一階段處理過
}
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);
}
}
// 首先, 調用PriorityOrdered實現的BeanFactory後置處理器.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 其次, 調用Ordered實現.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// 最後, 調用其他BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// 清除緩存的合併bean定義,因爲後處理器可能具有修改了原始元數據,例如替換值中的佔位符...
beanFactory.clearMetadataCache();
}
// 重點關注
——> private static void invokeBeanFactoryPostProcessors(
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanFactory(beanFactory);
}
}
BeanFactory後置處理器的執行和註冊一樣,也會分爲三種優先級,PriorityOrdered—>Ordered—>其他BeanFactoryPostProcessors,演示中自定義的MyBeanFactoryPostProcessor 屬於最後一級。
執行時,直接從IOC中獲取到通過Bean名稱到對應的BeanFactoryPostProcessor對象,最後調用postProcessBeanFactory方法,postProcessBeanFactory就是我們MyBeanFactoryPostProcessor 中實現的BeanFactory後置增強方法。
BeanFactory後置處理器總結
Spring首先通過類路徑加載器進行掃包同時完成BeanFactoryPost後置處理器的註冊,註冊完成後,根據指定的BeanName從容器中獲取BeanFactoryPost後置處理器,並執行postProcessBeanFactory方法,實現增強。
BeanFactory後置處理器在IOC初始化掃描後Bean實例構造方法執行前執行,可以實現對Bean實例的增強。但應用面比較雞肋,而且在後續刷新上下文過程中Spring提供了更加強大的Bean前置增強處理器以及後置增強處理器。
這也是AOP的實現的依仗,下面我們開始它的分析!
結構圖
刷新上下文階段 - 註冊Bean增強處理器
Spring爲Bean實例提供了兩種Bean增強處理器,前置/後置處理器。也正是因爲IOC提供的增強處理器,使得AOP可以在類初始化之前織入代碼實現增強,這個過程是通過動態代理實現的。
想要在後續使用增強處理器,首先將其注入到容器中,下面我們來看一下它的調用鏈。
非常建議開啓AOP註解@EnableAspectJAutoProxy(MySpringConfig上標註),這樣可以更加直觀的進行調試。
調用鏈
// 調用過程從AbstractApplicationContext.refresh()開始registerBeanPostProcessors(beanFactory);
——> protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
// 在之前階段IOC已經做了非常多的工作,使得後續注入工作變得非常簡單
——> public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// 與之前注入一樣,
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// 排序 PriorityOrdered —> Ordered —> 其他.
// 省略部分代碼……
// 首先, 註冊PriorityOrdered實現的BeanPostProcessors.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// 其次, 註冊Ordered實現的BeanPostProcessors.
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);
// 然後,註冊其他的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);
// 最後, 重新註冊所有內部BeanPostProcessor.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// 重新註冊用於將內部bean檢測爲ApplicationListener的後處理器,將其移至處理器鏈的末尾(用於拾取代理等).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
——> private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
——> public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
// 省略日誌部分代碼……
this.beanPostProcessors.add(beanPostProcessor);
}
——> private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
註冊Bean增強處理器總結
實現一個增強處理器,只需要實現BeanPostProcessor接口。Spring對於這類增強處理器,使用CopyOnWriteArrayList進行存儲,間接的說明了這類數據是讀多寫少的。
結構圖:
刷新上下文階段 - 實例化所有剩餘的單例Bean
這一階段需要將之前階段注入的Bean進行實例化(調用構造),除此之外在實例化過程中實現增強。
調用鏈
// 調用過程從AbstractApplicationContext.refresh()開始finishBeanFactoryInitialization(beanFactory);
——> protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 省略部分組件初始化代碼……
// 實例化所有剩餘的(非延遲初始化)單例
beanFactory.preInstantiateSingletons();
}
// 查看preInstantiateSingletons的默認實現DefaultListableBeanFactory
——> public void preInstantiateSingletons() throws BeansException {
// 省略獲取所有實例代碼……
// 非惰性單例bean的初始化...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
// 觸發所有適用bean的初始化後回調...
// 忽略部分代碼……
}
// 我們只看關鍵代碼,Bean如何實例化的?
——> public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
// doGetBean代碼比較長,主要區別是否有構造方法,有參/無參構造、單例/原型等,最終調用createBean進行創建,這裏就不貼代碼了。
//IDEA Ctrl+Alt+B 查看createBean的默認實現AbstractAutowireCapableBeanFactory
——> protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
// createBean中主要是爲後階段反射以及後置增強做準備工作。
// 部分準備代碼……
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
// 忽略catch……
}
——> protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 忽略部分代碼……
// 允許後處理器修改合併的bean定義。
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 主要解決生成Bean實例的循環依賴問題
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 初始化bean實例.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
// 初始化給定的bean實例,應用工廠回調以及init方法和bean後處理器
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 省略部分代碼……
return exposedObject;
}
——> protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 調用實現Aware接口方法,只針對三種Aware接口BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// Bean前置增強處理器
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 反射生成Bean實例
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// Bean前置增強處理器
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
——> public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
——> public List<BeanPostProcessor> getBeanPostProcessors() {
return this.beanPostProcessors;
}
還記得Spring注入Bean增強處理器時存放的CopyOnWriteArrayList名稱嗎?是不是也是beanPostProcessors?所以,我們來總結一下。
實例化所有剩餘的Bean總結
通過以上分析,我們可以知道,加載的過程大概是這樣的:
- Spring IOC在掃描時將所有Bean實例注入到了容器,此時容器中的實例只是一個BeanName與實例Class對象的映射;
- 然後,又將Bean增強處理器裝配到了容器中;
- 隨後,循環實例化所有Bean,並在實例化過程中獲取所有Bean前置增強處理器,執行前置增強;
- 之後,通過反射技術實例化Bean;
- 最後,實例化結束,執行所有Bean後置增強處理器,並刷新容器實例。
結構圖
AOP源碼分析
從上訴分析中我們瞭解到,Spring IOC採用一個ConcurrentHashMap來存儲BeanDefinition(Bean實例)。
同時,爲所有的Bean提供了Bean的前置/後置增強處理器,而且只需要實現BeanPostProcessor接口IOC就會在啓動時我們執行對應的增強方法。
上面這兩點恰恰就是AOP的關鍵,接下來我們就看看AOP在Bean的增強處理器中做了什麼事。
環境搭建
// 1、MySpringConfig加上@EnableAspectJAutoProxy標註
@Aspect
@Component
public class LoginAop {
/**
* @Pointcut 定義切入點
*
* @Pointcut(value = "execution (* com.lming.service.*..*.*(..))") service.所有子包 下面所有的類所有的方案
*/
@Pointcut("execution (* com.lming.service..*.*(..))")
public void loginAop() {
}
/**
* 前置通知
*
* @param joinPoint
*/
@Before("loginAop()")
public void doBefore(JoinPoint joinPoint) {
System.out.println(">>>>>>>前置通知<<<<<<<<<<< ");
}
/**
* 後置通知
*/
@After("loginAop()")
public void doAfter(JoinPoint joinPoint) {
System.out.println(">>>>>>>>後置通知<<<<<<<<<");
}
/**
* 環繞通知
*
* @param joinPoint
*/
@Around("loginAop()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(">>>>環繞通知之前執行...>>>>>>");
joinPoint.proceed();// 執行目標方案
System.out.println(">>>>環繞通知之後執行...>>>>>>");
}
/**
* 運行通知
*/
@AfterReturning("loginAop()")
public void afterReturning(JoinPoint joinPoint) {
System.out.println("運行通知執行.....");
}
/**
* 異常通知
*
* @param joinPoint
*/
@AfterThrowing("loginAop()")
public void afterThrowing(JoinPoint joinPoint) {
System.out.println(">>>>>異常通知");
}
}
@Component
public class MemberServiceImpl implements InitializingBean, MemberService {
public MemberServiceImpl() {
System.out.println("執行無參構造函數....");
}
public String login(String userName, String passWord) {
int i = 1 / 0;
System.out.println(">>>>正在執行登陸業務邏輯>>>>> userName:" + userName + "passWord:" + passWord);
return ">>>>登陸業務邏輯..<<<<";
}
public void afterPropertiesSet() throws Exception {
System.out.println("執行自定義bean的init方法");
}
}
public interface MemberService {
public String login(String userName, String passWord);
}
AOP源碼分析
分析一個框架的源碼,首先需要知道它解決了什麼問題、怎麼使用的、瞭解他的大致原理,這在我們分析源碼時是不可或缺的知識。
隨後,分析源碼首先需要有一個目的,然後找到入口,步步深入,並記錄整個過程,這也是非常重要的,特別想面對Spring這種代碼非常緊密的框架時,書籤筆跡可以幫你快速定位代碼。
目的: AOP在Bean的增強處理器中做了什麼事?如何實現的切面編程?
入口: @EnableAspectJAutoProxy
調用鏈
@Import(AspectJAutoProxyRegistrar.class)
// ImportBeanDefinitionRegistrar 手動注入
——> class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
// 將創建好的AOP代理注入到IOC,BeanName = internalAutoProxyCreator
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
——> public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
// 注入了AnnotationAwareAspectJAutoProxyCreator
——> public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
@EnableAspectJAutoProxy註解最終注入了AnnotationAwareAspectJAutoProxyCreator類。
這時候線索中斷了,接下來應該調用哪個方法呢?
我們查看一下AnnotationAwareAspectJAutoProxyCreator類圖:
我們可以發現在AnnotationAwareAspectJAutoProxyCreator的類圖中實現了BeanPostProcessor、ProxyConfig4、BeanFactoryAware5 等幾個超類。
在IOC中我們敘述過,實現BeanPostProcessor可以對Bean進行增強。IOC在第三階段刷新上下文時會調用所有BeanPostProcessor實現的前置增強postProcessBeforeInitialization以及後置增強方法postProcessAfterInitialization。
也就是說,AOP這時候注入的AnnotationAwareAspectJAutoProxyCreator類中(間接)實現了這兩個方法,並且在IOC刷新上下文時會被調用,所以找到它們就可以繼續分析。
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
// 如果Bean被子類標識爲要代理的Bean,則使用配置的攔截器創建代理。
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
最終,我們在AbstractAutoProxyCreator中找到了他們,AOP在其前置增強中並未做任何操作,所以我們關注後置增強,通過標註我們可以發現它是在創建一個代理。
我們知道代理分爲兩種,動態代理和靜態代理6,這裏的程序必然是使用動態代理,那麼動態代理又分爲兩種方式創建JDK、CGlib動態代理,AOP是採用的何種方式進行創建的呢?
繼續調用鏈:
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;
}
// 如果有建議,請創建代理。
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;
}
——> protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
// 依靠是否具有實現類(setProxyTargetClass),判斷使用JDK還是CGlib動態代理
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
// 設置代理類型
proxyFactory.setProxyTargetClass(true);
}
else {
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);
}
我們首先觀察AOP是如何選用何種方式創建代理類的,再來看具體的創建過程。
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
// 查看createAopProxy(this)的默認實現DefaultAopProxyFactory
——> 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);
}
}
所以我們可以得知,Spring AOP依據getTargetClass選擇何種動態代理來創建實例,也就是說Spring AOP根據當前類是否是一個實現類來選擇具體的動態代理創建方式。
若當前Bean實例是接口的實現類,則使用JDK動態代理創建;
若當前Bean實例沒有實現任何接口,則使用CGlib動態代理創建。
回到,getProxy,繼續觀察getProxy(classLoader)是如何創建動態代理的,查看getProxy的JdkDynamicAopProxy實現,發現JdkDynamicAopProxy實現了InvocationHandler接口。
這時候我們就明白了,通過JDK創建動態代理必須實現InvocationHandler接口,實現invoke方法,通過Proxy.newProxyInstance()即可動態的創建一個代理類。
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
CglibAopProxy的getProxy()實現調用了getCallbacks(),getCallbacks()根據ProxyConfig4中targetSource判斷使用什麼方式創建代理類。
Cglib方式默認提供兩種靜態內部內實現,StaticUnadvisedExposedInterceptor(單例)、DynamicUnadvisedExposedInterceptor(原型),根據targetSource判斷Bean實例是單例還是原型,選擇不同的方式管理代理類7。
最後,我們獲取到了代理類對象的話,就可以在invoke方法中,攔截切面配置的需要織入的方法,對其進行前置/後置/異常/環繞/事務等增強操作。
但是,這些增強並不是無需執行的,那麼Spring怎麼保證這些增強執行順序的呢?Spring通過遞歸實現了一個調用鏈,通過控制遞歸的條件可以保證不同類型增強代碼的鏈型執行順序。
AOP源碼總結
Spring AOP通過IOC提供實現BeanPostProcessor接口的來執行後置增強方法,在後置增強方法中對實例Bean創建代理對象,並根據實例是否爲接口實現類來判斷採用JDK還是CGlib動態代理。
當被代理的對象的方法執行時,判斷是否屬於需要織入切面的方法,切面配置由IOC刷新上下文是注入容器。
AOP是支持多種增強的(前置、後置、異常、環繞等),而其執行的順序則是通過遞歸實現的調用鏈設計模式,保證不同增強代碼的鏈型執行順序。
- 第一步,通過@import手動注入AspectJAutoProxyRegistrar.class(ImportBeanDefinitionRegistrar的實現)到IOC容器中;
- 第二步,spectJAutoProxyRegistrar.class最終會手動注入BeanPostProcessor接口的實現類實例;
- 第三步,IOC啓動第三階段刷新上下文,完成所有掃包到的Bean實例注入時,會對所有Bean實例執行所有的BeanPostProcessor(BeanPostProcessor的實現會先於Bean實例注入到IOC容器);
- 第四步,BeanPostProcessor主要功能是可以實現對Bean實例的增強,AOP在增強過程中根據Bean實例是否爲接口實現類判斷使用何種動態代理對Bean進行代理;
- 第五步,AOP通過BeanFactoryAware可以獲取到IOC容器中掃包過程中注入進去的AOP配置信息,最終被代理的Bean實例的方法(通常是service業務包下面的方法)開始執行;
- 第六步方法被代理後並不會直接執行,而是交由**jdk的invoke()或cglib的intercept()**代理執行,最終AOP通過代理規則判斷當前執行的方法是否需要執行增強代碼了(增強代碼則是通過反射執行的)。
- 最後,AOP通過遞歸實現切面方法執行邏輯的調用鏈,保證不同增強代碼的鏈型執行順序。
總結
本文重點考量IOC、AOP的源碼實現以及它們之間的內在聯繫,忽略了其他的散項代碼。Spring中還包含了非常多的設計模式以及優秀的設計理念,這是值得我們仔細考量的,比如AOP中的調用鏈模式、Bean實例的循環依賴問題等等。
有興趣的同學就去幹它吧!
好啦!本文到這裏就結束啦,篇幅比較長,耐心閱讀,相信你會有所得~
差點忘了,最後的分析圖,趕緊貼上。
Spring5.X IOC與AOP源碼分析圖:
最後,附上一張分析書籤。
表示針對每次請求都會產生一個新的Bean對象,並且該Bean對象僅在當前Http請求內有效。 ↩︎
作用域表示煤氣請求都會產生一個新的Bean對象,並且該Bean僅在當前Http session內有效。 ↩︎
@ComponentScan中的includeFilters、excludeFilters都將在此時被解析。 ↩︎
ProxyConfigAOP創建代理的配置API。 ↩︎ ↩︎
BeanFactoryAware實現了BeanFactoryAware接口的bean,可以直接通過beanfactory來訪問spring的容器。 ↩︎
對應到實例中就是LoginAop。 ↩︎