spring-ioc如何将一个接口变成springbean

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 单例对象

完。

猜你喜欢

转载自blog.csdn.net/qq_38108719/article/details/100539913