只有接口,没有实现类。spring是如何注入空接口并执行代码的?
里面涉及到了两个姿势点:
1.jdk动态代理,java运行只有接口,没有实现类,生成一个可执行的对象
2.spring FactoryBean ,通过spring提供的bean工厂,可是轻松的根据参数实例化需要的bean
以上两者结合,就可以实现只有接口也能注入并使用
只有接口生成一个可执行的类
一个被代理的空接口
public interface MyInterface {
@Select("select 'testSql'")
void myTest(String s);
}
代理类
public class MyMapperInvocation<T> implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String[] value1 = method.getAnnotation(Select.class).value();
System.out.println("selectById调用成功,拿到的sql:"+ Arrays.toString(value1)+"----拿到的参数:"+args[0]);
return null;
}
}
测试一下
public class Test {
public static void main(String[] args) throws Exception {
MyInterface myInterface = (MyInterface)Proxy.newProxyInstance(MyInterface.class.getClassLoader(),new Class[]{MyInterface.class},new MyMapperInvocation<>());
myInterface.myTest("myTest");
}
}
可以看到只有一个空接口,也可以执行代码
把空接口注入spring,像mybatis的mapper一样执行
通过后置处理器,把代理类注入到spring
@Configuration
public class AnnotationScannerConfigurer implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MyFactoryBean.class);//定义工厂类
builder.addPropertyValue("proxyInstanceClass", MyInterface.class);//设置工厂类的参数,工厂类根据参数生成代理对象
BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(builder.getBeanDefinition(), "myInterface");//设置代理对象的beanName
BeanDefinitionReaderUtils.registerBeanDefinition(beanDefinitionHolder, beanDefinitionRegistry);//添加到spring容器定义中
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("----postProcessBeanFactory----");
}
}
测试代码
@Slf4j
@RestController
public class MyController {
@Resource
private MyInterface myInterface;
@GetMapping("/test9")
public String test9() {
myInterface.myTest("test9");
return "ok";
}
}
发现依然可以执行