interface-->proxy object-->springbean
首先确定的是将一个接口变成一个对象,JDK动态代理再合适不过,但是将代理对象交给spring管理该怎么做呢?
我们将一个对象交给spring管理有哪些方式呢?
BeanFactory,FactoryBean,ImportSelector,工厂方法(xml配置 factory-method="createObject")
前面介绍过BeanFactory,FactoryBean
现在说下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
实现该接口可以将一个Java object 变成springbean
但是需要该类名名称,而代理对象类名称不固定($Proxy0,0是会变的)
spring提供了这样一个接口ImportBeanDefinitionRegistrar,我们组合FactoryBean接口一起来看代码实现
我们先定义一个接口
//接口
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;
}
}
我们先看重写的getObject()方法,直接将代理对象返回来,但是我们不能再来实现ImportSelector这个接口,上面已经提到了
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);
}
}
使用注解来开启spring的该接口实现
@Retention(RetentionPolicy.RUNTIME)
@Import(TestImportBeanDifinitionRegistrar.class)
public @interface TestScanMapper {
}
最后可直接使用main方法测试从容器中取出beanName 为 testMapper 单例对象
完。