interface-->proxy object-->springbean
The first thing to determine is to turn an interface into an object. JDK dynamic proxy is perfect, but what should I do to hand the proxy object to spring management?
What are the ways for us to hand over an object to spring for management?
BeanFactory, FactoryBean, ImportSelector, factory method (xml configuration factory-method="createObject")
I have introduced BeanFactory, FactoryBean
Now let’s talk about ImportSelector
//1扫描
@Configuration
@ComponentScan("org.springframework.spring.mybatis.*")
@TestScanMapper
@Import(TestImportSelector.class)//添加注解
public class AppConfig {
}
//2Java object
public class TestBo {
}
//3 自定义实现ImportSelector接口
public class TestImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{TestBo.class.getName()};
}
}
//4测试
public class MainDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println(ac.getBean(TestBo.class));
}
控制台打印结果
org.springframework.spring.mybatis.TestBo@5abca1e0
Implementing this interface can turn a Java object into a springbean
But the name of the class name is needed, and the proxy object class name is not fixed ($Proxy0,0 will change)
Spring provides such an interface ImportBeanDefinitionRegistrar, we combine the FactoryBean interface to see the code implementation
We first define an interface
//接口
public interface TestMapper {
//如果使用@MapperScan("org.springframework.spring.mybatis.*")注解请将getAll改成默认的list
@Select("select * from user where 1=1 and id=#{param}")
List<Map<Integer,String>> getAll(@Param("param") String param);
}
//实现FactoryBean接口 和 InvocationHandler接口
public class TestFactoryBean implements FactoryBean, InvocationHandler {
Class clazz;
public TestFactoryBean(Class clazz){//构造方法创建对象
this.clazz = clazz;
}
@Override//此处为获取代理方法的注解值,如:@Select("select * from user where uid=#{param}")打印sql。。。。。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class<?>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
Method method1 = proxy.getClass().getInterfaces()[0]
.getMethod(method.getName(), parameterTypes[0]);
Select select = method1.getDeclaredAnnotation(Select.class);
System.out.println(select.value()[0]);
}
return null;
}
@Override
public Object getObject() throws Exception {
Class[] clazzs = new Class[]{clazz};
Object proxy = Proxy.newProxyInstance(this.getClass().getClassLoader(), clazzs, this);
return proxy;
}
@Override
public Class<?> getObjectType() {
return clazz;
}
}
Let's first look at the rewritten getObject() method, which directly returns the proxy object, but we can no longer implement the ImportSelector interface, as mentioned above
public class TestImportBeanDifinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//扫描TestMapper这个接口,此处为模拟固定
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(TestMapper.class);
//得到一个beanDefinition
GenericBeanDefinition beanDefinition =(GenericBeanDefinition) builder.getBeanDefinition();
//设置beanclass
beanDefinition.setBeanClass(TestFactoryBean.class);
//通过构造方法新建对象
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("org.springframework.spring.mybatis.mapper.TestMapper");
//注册
registry.registerBeanDefinition("testMapper",beanDefinition);
}
}
Use annotations to enable spring's implementation of this interface
@Retention(RetentionPolicy.RUNTIME)
@Import(TestImportBeanDifinitionRegistrar.class)
public @interface TestScanMapper {
}
Finally, you can directly use the main method to test to remove the beanName from the container as the testMapper singleton object
Finish.