上一節主要說了bean註冊流程,下面再補充介紹其中關鍵的流程
再解析有@Config主機類時,也會處理@import
@Configuration
@ComponentScan("com.lmq.BaseService")
@Import("實現ImportBeanDefinitionRegistrar接口的類") //也可以是normal類,importSelect
public class AppConfig {
...........
//實現ImportBeanDefinitionRegistrar接口的類可以幫beanfactory加入某個bean對象,尤其是爲接口生成動態代理對象添加到spring的bean中,比如mybatis的mapper接口
spring註冊類方法:
1,register() //需要是一個類,無法參與生成bd
2, scan() //需要是一個類,或者註解,無法參與生成bd
3,ImportBeanDefinitionRegistrar, 好處參與生成bd ,好比MapperScan把@mapper接口變成對象,
@Documented
@Import({MapperScannerRegistrar.class})
public @interface MapperScan {
String[] value() default {};
其中MapperScannerRegistrar.class幫助註冊一個bean,
class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private ResourceLoader resourceLoader;
public MapperScannerRegistrar() {
}
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {。。。。//這裏registry上節講過是beanfactory
}
以上是例子,幫助理解ImportBeanDefinitionRegistrar
扯遠了
進去此方法,
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
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);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
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());
}
else {//import 普通類
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
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();
}
}
}
順便提下
AService{
@Autowired
Adao dao
}
對於Bservice extends Aservice
@Autowired
Adao dao 不會實例化
對於Bservice implements Aservice
@Autowired
Adao dao 會實例化
spring的自動裝配
繼續介紹,
@Configuration
@ComponentScan("com.lmq.BaseService")
//@Import("ImportBeanDefinitionRegistrar")
@Import(MyImportSelect.class) //相當於後面註冊UserController.class,並實例化添加到spring的bean
public class AppConfig {
。。。。。。。
}
public class MyImportSelect implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{UserController.class.getName()};
}
}
但引用@Import(MyImportSelect.class) ,UserController.class是需要存在項目的,無法創建代理對象,所以需要
ImportBeanDefinitionRegistrar;
這裏以uerMapper接口爲例來模仿mybatis的
mapperscan,註冊並添加實例對象到spring的bean中
其中UserMapper:
public interface UserMapper {
@Select("select * from user")
public List<User> findUserInfo(String name);
}
自定義MyImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
/**
* 得到bd,或者類信息,這裏對於接口類,假設實現創建代理對象,
*/
//這裏先寫死去爲某個接口去創建動態代理對象,其實可以模擬掃描註解的接口,類似mybatis的mapperscan, UserMapper是個接口
// UserMapper userMapper= (UserMapper) Proxy.newProxyInstance(MainTest.class.getClassLoader(), new Class[]{UserMapper.class}, new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// System.out.println("in proxy");
// return null;
// }
// });
// BeanDefinitionBuilder beanDefinitionBuilder= BeanDefinitionBuilder.genericBeanDefinition(userMapper.getClass()); //實際無法獲取代理類信息,使用factorybean
BeanDefinitionBuilder beanDefinitionBuilder= BeanDefinitionBuilder.genericBeanDefinition(UserMapper.class);
GenericBeanDefinition beanDefinition= (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();
//爲了傳參數,可以給bd添加構造函數
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("com.lmq.dao.UserMapper");
beanDefinition.setBeanClass(MyFactoryBean.class); //MyFactoryBean不能加Componenrt註解
registry.registerBeanDefinition("userMapper",beanDefinition);
}
}
其中
public class MyFactoryBean implements FactoryBean {
Class clazz;
public MyFactoryBean( Class clazz)
{
this.clazz=clazz;
}
@Override
public Object getObject() throws Exception {
Class []clazz= new Class[]{this.clazz};
Object proxy= (UserMapper) Proxy.newProxyInstance(MainTest.class.getClassLoader(),clazz, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("in proxy");
//爲了模仿mybatis執行sql
Method method1 =proxy.getClass().getInterfaces()[0].getMethod(method.getName(),String.class);
Select select =method1.getDeclaredAnnotation(Select.class);
System.out.println(select.value()[0]);
return null;
}
});
return proxy;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
這裏AppConfig引入MyImportBeanDefinitionRegistrar.class
@Configuration
@ComponentScan("com.lmq.BaseService")
@Import(MyImportBeanDefinitionRegistrar.class)
public class AppConfig {
}
AnnotationConfigApplicationContext lmqcontext = new AnnotationConfigApplicationContext(AppConfig.class);
//方式一
// LmqService lmq = lmqcontext.getBean(LmqService.class);
// LmqService lmq = lmqcontext.getBean("lmqService");
// lmq.printSys();
UserMapper lmq = (UserMapper) lmqcontext.getBean("userMapper");
lmq.findUserInfo();
輸出結果:
便實現往spring添加bean對象實例了哈,生成動態代理實例,類似mybtais mapperScan掃描接口.
核心是MyFactoryBean, 類似的其實mybatis有MapperFactoryBean
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface; //同樣是接口參數,MyFactoryBean參考類似的,目標是爲接口生成代理對象
private boolean addToConfig = true;
public MapperFactoryBean() {
}
......................
再看下MapperScannerRegistrar,也用了MapperFactoryBean
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private ResourceLoader resourceLoader;
public MapperScannerRegistrar() {
}
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
if (this.resourceLoader != null) {
scanner.setResourceLoader(this.resourceLoader);
}
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
scanner.setAnnotationClass(annotationClass);
}
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
scanner.setMarkerInterface(markerInterface);
}
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
scanner.setBeanNameGenerator((BeanNameGenerator)BeanUtils.instantiateClass(generatorClass));
}
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
scanner.setMapperFactoryBean((MapperFactoryBean)BeanUtils.instantiateClass(mapperFactoryBeanClass));
}
scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
List<String> basePackages = new ArrayList();
String[] var10 = annoAttrs.getStringArray("value");
int var11 = var10.length;
int var12;
String pkg;
for(var12 = 0; var12 < var11; ++var12) {
pkg = var10[var12];
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
var10 = annoAttrs.getStringArray("basePackages");
var11 = var10.length;
for(var12 = 0; var12 < var11; ++var12) {
pkg = var10[var12];
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
Class[] var14 = annoAttrs.getClassArray("basePackageClasses");
var11 = var14.length;
for(var12 = 0; var12 < var11; ++var12) {
Class<?> clazz = var14[var12];
basePackages.add(ClassUtils.getPackageName(clazz));
}
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));
}
省略