之前学习mybatis扫描mapper到容器,逻辑和细节太多,于是先从一个最小的代码例子入手,找找感觉
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
public @interface MyLearning {
}
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE})
@Import({MyScannerRegistrar.class})
public @interface MyLearningScan {
String[] value() default {};
}
@MyLearning
public interface HelloTest {
String f1();
}
public class MyScannerRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MyLearningScan.class.getName()));
MyScanner myScanner = new MyScanner(registry);
// 扫描MyLearningScan注解中的定义的包路径
myScanner.doScan(annotationAttributes.getStringArray("value"));
}
}
public class MyScanner extends ClassPathBeanDefinitionScanner {
public MyScanner(BeanDefinitionRegistry registry) {
super(registry, false);
// 添加需要扫描的注解
addIncludeFilter(new AnnotationTypeFilter(MyLearning.class));
}
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 扫描到basePackages中所有被注解MyLearning标记的接口的Bean定义
Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
for (BeanDefinitionHolder holder : beanDefinitionHolders) {
BeanDefinition definition = holder.getBeanDefinition();
String beanClassName = definition.getBeanClassName();
// 使用指定的Bean来产生实例
definition.setBeanClassName(MyFactoryBean.class.getName());
// 指定BeanClass构造函数的参数
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
}
return beanDefinitionHolders;
}
// 这句override很重要,父类默认注解标记的必须是实现类,这里的逻辑改为标记的是接口
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
}
public class MyFactoryBean<T> implements FactoryBean<T> {
private final Class<T> interfaceType;
public MyFactoryBean(Class<T> interfaceType) {
this.interfaceType = interfaceType;
}
@Override
public T getObject() throws Exception {
return (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), new Class[]{interfaceType}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
return "hello world";
}
}
});
}
@Override
public Class<?> getObjectType() {
return this.interfaceType;
// 这里返回值很重要,不然只能通过@Resource注入,通过ConfigurableApplicationContext.getBean(Class<T> requiredType)可知会调用这里,先通过类型获取beanName,再通过beanName获取bean
}
}
@MyLearningScan("com.example.mybatislearning.mymapper")
@SpringBootTest
class MybatisLearningApplicationTests {
@Autowired
private HelloTest helloTest;
@Test
void contextLoads() {
String r = helloTest.f1();
System.out.println("r:" + r);
}
}