Spring中ImportBeanDefinitionRegistrar源碼和使用方式
ImportBeanDefinitionRegistrar源碼和使用
第一步
定義的Mapper層:
@Mapper
public interface PayMapper {
@Select("select * from city")
public List<Map<String,Object>> list();
}第二步
使用FactoryBean,通過getObject方式,創(chuàng)建一個對象,放入到spring容器中,這里使用代理對象,放入到spring容器中。
public class MyFactoryBean implements FactoryBean, InvocationHandler {
private Class aClass;
public MyFactoryBean(Class aClass) {
this.aClass = aClass;
}
@Override
public Object getObject() throws Exception {
Class[] interfaces = new Class[]{aClass};
Object proxyInstance = Proxy.newProxyInstance(this.getClass().getClassLoader(), interfaces, this);
return proxyInstance;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理對象,獲取sql語句");
Method method1 = proxy.getClass().getInterfaces()[0].getMethod(method.getName(), null);
Select declaredAnnotation = method1.getDeclaredAnnotation(Select.class);
System.out.println(declaredAnnotation.value()[0]);
return null;
}
}第三步
spring的ImportBeanDefinitionRegistrar處理器,可以對于spring的BeanDefinitionMap進行操作,可以修改Bean的描述,此時還沒有變成對象,這里是把創(chuàng)建注入的類型,創(chuàng)建了構(gòu)造方法中需要的接口,最后取Bean的名字:payServiceTest,一個BeanDefinition描述。
public class MyImportDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(PayMapper.class);
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
//TODO: 注入類型
beanDefinition.setBeanClass(MyFactoryBean.class);
//TODO: 注入構(gòu)造方法
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("com.luoyan.dao.mapper.PayMapper");
//TODO: 放入到beanDefinitionMap中
registry.registerBeanDefinition("payServiceTest",beanDefinition);
}
}第四步
自定義注解,把@Import(MyImportDefinitionRegistrar.class)注解,MyImportDefinitionRegistrar類放入到sprinig中運行。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MyImportDefinitionRegistrar.class)
public @interface LuoyanImportBeanDefinitionRegistrar {
}第五步
配置類:需要使用自定義注解@LuoyanImportBeanDefinitionRegistrar,把后置處理器的代碼內(nèi)容執(zhí)行。
@Configuration
@ComponentScan("com.luoyan")
@MapperScan("com.luoyan.dao.mapper")
@LuoyanImportBeanDefinitionRegistrar
public class AppConfig {
}第六步
啟動類:
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfig.class);
applicationContext.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
applicationContext.refresh();
PayMapper payServiceTest = (PayMapper) applicationContext.getBean("payServiceTest");
payServiceTest.list();
}源碼:
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
/**
*
* 因為@Import(xxx.class,xxxx.class)這里可以放多個
* importCandidates:表示被放在@Import注解中的class類的報名+類名。比如:com.shadow.imports.MyImportSelector.
* candidate:就表示com.shadow.imports.MyImportSelector
*/
for (SourceClass candidate : importCandidates) {
/**
* ImportSelector,判斷這個MyImportSelector.class是否實現(xiàn)了ImportSelector類
*/
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
//得到Import的類loadClass
Class<?> candidateClass = candidate.loadClass();
//反射實現(xiàn)一個對象
//這個instantiateClass()方法底層比較復雜
/******************************instantiateClass()這個方法很重要*************************************/
//new出來當前實現(xiàn)了ImportSelector接口的類對象
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
/**
* 這里重點
* 普通類就是加了@component類
*/
//得到所有字符串.//循環(huán)引用這類用的是遞歸,就是說你配置類上有了@Impont,但是你實現(xiàn)了ImportSelector類的類上還是有@Impont
//TODO: selector表示你實現(xiàn)ImportSelector接口的類的對象.
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
//把名字傳入得到importSourceClasses,把這個類添加到annotation這個變量中去了asSourceClasses()這個方法.
//importClassNames=com.shadow.service.TestService3
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
//然后又進行循環(huán)判斷了.繼續(xù)調(diào)用processImports()方法,剛剛進來的時候也是這個方法.
//遞歸,這里第二次調(diào)用processImports.
//如果是一個普通類,會進else
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
/**
* ImportBeanDefinitionRegistrar實現(xiàn)了這個接口的類放到了addImportBeanDefinitionRegistrar()方法
* importBeanDefinitionRegistrarsMap當中去了。
* 而
* 實現(xiàn)ImportSelector接口的類卻放到了configurationClassesMap當中去了。
* 所以在解析這些類的時候使用了不同的方法存放this.reader.loadBeanDefinitions(configClasses);
*
*/
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional com.luoyan.bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
/**
* 普通的
*/
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
/**
* 否則,加入到importStack后調(diào)用processConfigurationClass進行處理
* processConfiguration里面主要就是把類放到configrationClasses
* 可以看到普通類再掃描出來的時候就被注冊了
* 如果importSelector,回顯放到configurationClasses后面進行注冊
* 注意這里的processConfigurationClass前面已經(jīng)解釋過這個方法了
*/
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
//processConfigurationClass()這個方法,是繼續(xù)判斷當前普通類是否加了@Configuration注解
//candidate.asConfigClass(configClass)這個方法,是把通過@Import注解得到的類,執(zhí)行方法后,得到返回回來的類字符串,反射出來的類.放入到this.importedBy.add(importedBy);集合中
//真正導入到spring的BeanDefinitionMap中的時候使用到
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}源碼:
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) ->
/**
* 這個registrar.registerBeanDefinitions就是自己實現(xiàn)了ImportBeanDefinitionRegistrar接口
* 的類中邏輯,注冊到beanMap中的方法
*/
registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
基于獲取JAVA路徑,包括CLASSPATH外的路徑的方法詳解
本篇文章是對獲取JAVA路徑,包括CLASSPATH外的路徑的方法進行了詳細的分析介紹,需要的朋友參考下2013-05-05

