1、@Import
在聊ImportSelector和ImportBeanDefinitioRegistar之前需要先知道@Import。
@Import是写在我们的配置类上的,如下:
@Configuration
@Import({XXX.class,XXX2.class})
public class AppConfig {
}
当Spring扫描我们AppConfig后,就能拿到我们@Import中填的Class,并将其实例化后放到容器当中。
2、@Import中的三种类
@Import中填入的类可以区分为三种:
- 实现ImportSelector的类
- 实现ImportBeanDefinitionRegistrar的类
- 其余的普通类
3、ImportSelector
首先我们看看接口方法:
public interface ImportSelector {
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
* @return the class names, or an empty array if none
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
这里面要求返回一个String数组,该数组的值为类的全包名,例如:new String[]{"com.dh.AccountService","com.dh.UserService"},那么Spring就会将数组中的类实例化到容器当中。
该方法的参数AnnotationMetadata,此对象为我们@Import所在的类的元信息,例如其他注解,类信息等,在我们的示例代码中,此AnnotationMetadata中可以拿到Configuration注解,Import注解,Class信息,看下图:
这玩意应用场景:可以根据不同的情况来决定注入哪些类,在我们不考虑环境的情况下,可以直接@Bean注入类,也可以直接扫描,而当我们考虑环境的情况下,就有可能某些类并不注入,而且甚至可能需要逻辑代码校验来决定,那么就可以使用这个接口来进行逻辑代码校验并决定是否注入等。
4、ImportBeanDefinitionRegistrar
先看看接口方法
public interface ImportBeanDefinitionRegistrar {
/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
*/
void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}
这个相比上一个Selector更牛逼,它给了我们一个BeanDefinition的注册器(其实它也是我们的Bean工厂,而我们的Bean工程也是注册器),我们先看看BeanDefinitionRegistry实际上的类型:
而这里的AnnotationMetadata和上面的ImportSelector是一样的。
这玩意的应用场景:
例如Mybatis的代理我们Dao的操作,它需要干的事情是这样的:
1、拿到我们的需要代理的Mapper包并进行扫描
2、生成这些Mappeer的代理实现类,其中包含了它自己的业务规则
3、将生成的Mapper代理实现类存入Spring容器当中去
那么这里我们将Mapper代理实现类存入Spring容器这个步骤就需要我们的ImportBeanDefinitionRegistrar来实现。
MyBatis是如何做的呢?
它首先需要一个@MapperScan注解,这个注解里面包含了@Import注解,并导入了它自己ImportBeanDefinitionRegistrar实现类,名字叫MapperScannerRegistrar
,此类当中首先扫描我们MapperScan中value的包,然后循环这些Mapper,完了再创建BeanDefinition,再通过FactoryBean实例化这些Mapper的代理类,并将这些BeanDefinition存入spring容器中,然后Spring容器就会实例化这些代理类。
5、使用ImportBeanDefinitionRegistar模拟一下Mybatis代理Mapper
5.1、自定义注解Select
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Select {
public String value() default "";
}
5.2、TestMyFactoryBean
@SuppressWarnings({"rawtypes", "unchecked"})
public class TestMyFactoryBean implements FactoryBean,InvocationHandler {
@SuppressWarnings({"rawtypes", "unchecked"})
Class interfaces;
@SuppressWarnings({"rawtypes", "unchecked"})
public TestMyFactoryBean(Class interfaces) {
this.interfaces = interfaces;
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public Object getObject() throws Exception {
Class[] classes = new Class[]{interfaces};
return Proxy.newProxyInstance(this.getClass().getClassLoader(), classes,this);
//return userDao;
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public Class getObjectType() {
return interfaces;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Select select = method.getAnnotation(Select.class);
if (Objects.nonNull(select)) {
System.out.println("method : "+method.getName()+"run sql :" + select.value());
}
return "this is return value";
}
}
5.3、UserDao
public interface UserDao {
@Select("select * from user were id = ?")
public Object findById();
}
5.4、MyImportBeanDefinitionRegister
public class MyImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
/* 假装这是我们扫描到的Mapper */
UserDao userDao;
/* 生成一个FactoryBean,Mybatis对应的 */
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(TestMyFactoryBean.class);
/* 从Builder中拿到BeanDefinition */
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
/* 添加构造器参数 */
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserDao.class.getName());
registry.registerBeanDefinition("userDao",beanDefinition);
}
}
5.5、AppConfig
@Configuration
@Import(MyImportBeanDefinitionRegister.class)
public class AppConfig {
}
5.6、Main1
public class Main1 {
/**
* 测试方法1
* */
public static void test1(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfig.class);
applicationContext.refresh();
UserDao userDao = applicationContext.getBean(UserDao.class);
System.out.println(userDao.findById());
}
public static void main(String[] args) {
test1();
}
}
这个代码解释:
@Select:这个是用来模拟Mybatis的Select注解的,里面只有一个value参数
TestMyFactoryBean:这个涉及到Spring中FactoryBean的知识,当我们的类实现FactoryBean这个接口后,那么Spring将不会直接把我们这个类的实例对象当做Bean存入到容器当中,而是将实现的getObject()方法的返回值实例对象当做Bean存入到容器当中去
UserDao:模拟我们Mybatis当中的Mapper接口(实际上它就应该是一个Mapper接口)
MyImportBeanDefinitionRegister:实现了我们ImportBeanDefinitionRegistar接口的实现类,在这里面我们假装UserDao.class是我们扫描到的,然后生成一个BeanDefinitionBuilder,然后再设置其FactoryBean实现类中构造器的参数,然后再将我们生成的BeanDefinition存入到Spring当中去
AppConfig:配置类,其中注意我们@Import中填入了我们的MyImportBeanDefinitionRegister
Main1:主类
这里我们可能有疑问,Mybatis是使用MapperScan的,然后在MapperScan中@import了它自己的ImportBeanDefinitionRegistar实现类,而我们这里直接在配置类里面自己@Import了,那么这块需要涉及到自定义扫描我们的注解,这样才能让我们扫描到MapperScan并做后序解析,这块内容是其他方面的知识,后序随笔中会加入这些内容,这里就不对其进行过于的描述,主要是要让大家明白@Import中的三个类,以及其应用场景。
6、源码解析Import的操作在哪
1、我们从底下往上看,首先是我们的Main1中去调用test1,这个是我自己写的Main方法, 不重要:
public class Main1 {
public static void test1(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfig.class);
applicationContext.refresh(); // 进入到此方法中
UserDao userDao = applicationContext.getBean(UserDao.class);
System.out.println(userDao.findById());
}
public static void main(String[] args) {
test1();
}
}
2、然后我们看applicationContext中的refresh方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.,准备提前工作,例如设置一些标志位,开始时间等
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.,获取BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.,做一些Bean的准备工作
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 空方法
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); // =================================line1
// Register bean processors that intercept bean creation.注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
此refresh方法中进入到line1方法中,line1这个方法主要是用于执行我们自己定义的BeanFactoryPostProcessor和Spring内置的BeanFactoryPostProcessor,进入看line1下的代码。
3、进入invokeBeanFactoryPostProcessors方法
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // line1
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
此方法会进入到line1当中去,在我们的BeanFactoryPostProcessors当中有三种来源:
1、Spring内置的
2、我们手动加入到Spring的
3、我们自定义后被Spring扫描到的
这里的getBeanFactoryPostProcessor是我们自己手动加入到Spring的。
4、进入到invokeBeanFactoryPostProcessors方法中
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
/* 用来存放我们手动添加的BeanFactoryPostProcessor */
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
/* 用来存放我们手动添加的BeanDefinitionRegistryPostProcessor */
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
/* 此处判断我们手动添加的BeanPostProcessor是否为BeanDefinitionRegistryPostProcessor类型的,如果是,那么则直接执行以下,否则就到后面去执行默认自带的BeanDefinitionRegistryPostProcessor */
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
/* 判断BeanPostProcessor的类型是否为BeanDefinitionRegistryPostProcessor,但注意它的类型一定为BeanFactoryPostProcessor */
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
/* 用来存放Spring内置的BeanDefinitionRegistryPostProcessor */
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// BeanDefinitionRegistry
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.拿到所有实现BeanDefinitionRegistryPostProcessor接口的BeanFactoryPostProcessor,并放置到currentRegistryProcessors中
/* 拿到实现了BeanDefinitionRegistryPostProcessor接口的类名的beanName */
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
/* 循环的放到currentRegistryProcessors */
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
/** 对Processor进行排序,该排序规则对象的设置位置为:
* org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)
* beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
* 此时currentRegistryProcessors中存放的时spring内置的,registryProcessors本身放置的是我们自定义的,需要将两个给合并起来
*/
sortPostProcessors(currentRegistryProcessors, beanFactory);
/* 将我们手动加入的BeanDefinitionRegistryPostProcessor和spring内置的合并到一起 */
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); // line1
currentRegistryProcessors.clear();/* 清除list */
................很多代码
}
这里重点是看line1,至于上面的代码操作我大概解释一下:
首先将我们手动给Spring的BeanFactoryPostProcessor执行,然后哦从容器当中拿实现了BeanDefinitionRegistryPostProcessor(BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子类,做了一个扩展)接口的实现类(注意此时Spring还未扫描包,所以这里能拿出来的就只有内置的),然后将这些内置的BeanDefinitionRegistryPostProcessor排个序,完了再拿去执行,那么执行就是invokeBeanDefinitionRegistryPostProcessors这行代码。
5、进入invokeBeanDefinitionRegistryPostProcessors方法
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry); // line1
}
}
这里面的postProcessors是一个数组,因为内置的BeanDefinitionRegistryPostProcessor可能有多个,但当前只一个,名字叫ConfigurationClassPostProcessor,然后我们进入这个类的postProcessBeanDefinitionRegistry方法。
6、ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry); // line1
}
不关系这些校验,进入到line1当中
7、进入processConfigBeanDefinitions
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();/*获取所有BeanDefinition中的Bean的名称*/
/* 循环所有的类,看是否为配置类,如果是,则需要对这些类进行解析 */
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);/* 循环拿到所有的BeanDefiniton */
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || /* 判断该类是否已经加载过,如果已经加载过,那么则打一个log */
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
/* 说明此类已经加载过,无需再加载 */
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
/* 如果没加载过,那么判断此类是否是配置类,如果是则加入到configCandidates中后面会对这些配置类进行解析, */
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { /* */
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 如果配置类一个都没有,那就没必要继续往下一步走了
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable,对前面解析出来带有Configration相关的集合排序,此排序值取决于该这些类上面放置的@Order注解
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context,如果我们设置了BeanName生成器,那么则使用我们的,否则就使用Spring内置的
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {/* 解析这些类 */
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses); // line1
..............很多代码
}
重点看line1,对上面的代码大概描述一下:
1、拿到Spring当中当前所有的Bean的名称
2、循环遍历这些类
2.1、如果当前Bean已经被解析过了,那么不操作,
2..2、如果当前Bean未解析,那么判断其是否为配置类,如果是则加入到集合,不是则不操作。
判断是否为配置类的依据为:是否加入了@Configuration、是否加入了@Import、@Component、@ImportResource、@ComponentScan其中一个,如果加入了@Configuration那么则不会再去判断后面的
3、判断是否存在配置类,不存在则停止
4、对配置类进行排序,排序规则为其@Order注解
5、获取BeanName生成器,如果没配置则会获取默认的
6、创建配置类解析器
7、do...while的解析我们的这些类
8、parser.parse(candidates);解析这些类,
注意这个方法,这里面有我们这次很重要的@Import(这里不解析其他注解例如扫描包,导入xml等),这里面@Import的类我们上面说了三种,除了ImportBeanDefinitionRegistart以外,其他的类都会立即被解析存放Spring到BeanDefinition或调用其ImportSelector的方法,而我们的ImportBeanDefinitionRegistart则会单独的北方知道parser的configutationClasses集合当中。
9、到了我们重点的line1当中,这里面对我们上面解析拿到的ImportBeanDefinitionRegistart实现类单独的拿去执行
8、进入到this.reader.loadBeanDefinitions(configClasses);
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator); // line1
}
}
同样我们的ImportBeanDefinitionRegistart实现类可能有多个,这里挨个去执行,而我们本次案例中只有一个,为:MyImportBeanDefinitionRegister,这个类存在的地方在ConfigurationClass的importBeanDefinitionRegistrars属性中:
9、进入到loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);方法中
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); // line1
}
可以看到line1中就是将我们刚才展示的importBeanDefinitionRegistrars拿出来传给这个方法。
10、进入到loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) ->
registrar.registerBeanDefinitions(metadata, this.registry)); /// line1
}
这没什么好说的,就是去执行registerBeanDefinitions方法,此时我们看registrar,它就是我们的MyImportBeanDefinitionRegister
11、进入到registrar.registerBeanDefinitions(metadata, this.registry)
此时就到了我们自己定义的ImportBeanDefinitionRegistrar中来,注意这里的importingClassMetadata就是我们前面ConfigurationClass的importBeanDefinitionRegistrars属性的值,而后者registry就是Bean工厂。
本次随笔到此结束,如文有误,深感抱歉,请提出后我改正,感激不尽,