ImportBeanDefinitionRegistrar是spring提供的一个扩展点,和ImportSelector不同的是,ImportBeanDefinitionRegistrar提供了一个注册器registry,用于注册BeanDefinition。此外,ImportBeanDefinitionRegistrar还可以参与BeanDefinition的创建过程。
Mybatis的@MapperScan扫描指定包下的接口(这些接口并没有实现类),进而完成数据库操作。底层正是基于动态代理和ImportBeanDefinitionRegistrar实现的。
下面自己来模拟实现一个吧:
public interface Mapper {
@MySelect("select * from user")
String query();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MySelect {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyBeanDefinitionRegistrar.class)
public @interface MyMapperScan {
String value();
}
public class MyBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar,ResourceLoaderAware {
ResourceLoader resourceLoader;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
try {
//获取@MyMapperScan包路径,并扫描
Map<String, Object> attributes = importingClassMetadata.getAnnotationAttributes(MyMapperScan.class.getName());
AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(attributes);
String packageName = annotationAttributes.getString("value");
String packageFileName=packageName.replace(".","/");
File[] files = resourceLoader.getResource(packageFileName).getFile().listFiles();
for (File file : files) {
System.out.println(file);
String fileName = file.getName().replace(".class", "");
Class<?> aClass = Class.forName(packageName+"."+fileName);
if(aClass.isInterface()&&!aClass.isAnnotation()){
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
GenericBeanDefinition beanDefinition = (GenericBeanDefinition) builder.getBeanDefinition();
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(packageName+"."+fileName);
beanDefinition.setBeanClass(MyFactoryBean.class);
registry.registerBeanDefinition(fileName,beanDefinition);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
public class MyFactoryBean implements FactoryBean,InvocationHandler {
//要代理的对象
Class clazz;
public MyFactoryBean(Class clazz) {
this.clazz = clazz;
}
@Override
public Object getObject() throws Exception {
Object proxy = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{clazz}, this);
return proxy;
}
@Override
public Class<?> getObjectType() {
return clazz;
}
@Override
public boolean isSingleton() {
return false;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取方法上的@MySelect
MySelect mySelect = method.getAnnotation(MySelect.class);
String value = mySelect.value();
System.out.println(value);
return null;
}
}
@Configuration
@MyMapperScan("com.su.spring.importBeanDefinitionRegistrar")
public class AppConfig {
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Mapper mapper = (Mapper) context.getBean("Mapper");
mapper.query();
}
}
这时候,我们已经拿到了sql,接下来就不进行jdbc操作了。
关于ImportBeanDefinitionRegistrar在spring当中什么时候解析处理的,见Spring-IoC之BeanFactory(Annotation)