有时候代码需要灵活的返回需要的一些对象,这时候我们往往用接口去承载返回的对象。尤其像spring这种框架,可以用@Resource的name属性进行区别。但是这种需要开发者在注入ioc中就提前申明name属性,在针对多个实现的情况下。作者今天看到另外一种姿势,主要是通过BeanFactory接口以及ApplicationContextInitializer、BeanDefinitionRegistryPostProcessor等接口去实现的。通过这些接口我们可以做更多的扩展,从而避免写name去标记的问题,其次更深化我们对spring的应用吧。
1、首先定义承载对象的接口;
public interface Bean {
}
2、定义BeanFactory,实现getObject方法。
public class MyBeanFactoryimplements FactoryBean{
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public static final Mapmap=new HashMap<>();
@Override
public T getObject() throws Exception {
if (CollectionUtils.isEmpty(map)||!map.containsKey("lele")){
synchronized (map){
return (T) execute();
}
}else{
return (T) map.get("lele");
}
}
private Object execute() {
Mybean mybean = new Mybean(name,age);
map.put("lele",mybean);
return mybean;
}
@Override
public Class getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
3、将BeanFactory注入到ioc容器。
public class MyBeanFactoryBean extends MyBeanFactory{
}
Spring注入bean装配厂工具类
public class MySpringContentUtils {
public static ConfigurableApplicationContext context;
public static ConfigurableApplicationContext getContext() {
return context;
}
public static void setContext(ConfigurableApplicationContext context) {
MySpringContentUtils.context = context;
}
public static void registerBean(String name, Class factoryClazz, Class beanClazz, MutablePropertyValues mpv) throws BeanDefinitionStoreException {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(beanClazz);
GenericBeanDefinition beanDefinition = (GenericBeanDefinition)beanDefinitionBuilder.getRawBeanDefinition();
beanDefinition.setBeanClass(factoryClazz == null ? beanClazz : factoryClazz);
beanDefinition.setPropertyValues(mpv);
BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry)context.getBeanFactory();
beanFactory.registerBeanDefinition(name, beanDefinition);
}
public staticT getBean(String name) throws BeansException {
return (T) context.getBean(name);
}
}
将MyBeanFactory注入到beanDefianition中
@Configuration
public class MyConfig implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
MutablePropertyValues mv=new MutablePropertyValues();
mv.add("name","jasldf");
mv.add("age","123");
MySpringContentUtils.registerBean("jk",MyBeanFactoryBean.class,Mybean.class,mv);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
}
上述中我们要想将MyBeanFactoryBean注入到IOC中,首先我们需要让MySpringContentUtils 拿到ioc,并用静态变量去引用其地址。这时候我们可以采用ApplicationContextInitializer的能力。
public class MyTianApplicationInitlize implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
MySpringContentUtils.setContext(configurableApplicationContext);
}
}
写完代码,我们在resources目录下创建META-INF文件夹,并创建spring.fatories文件,并填入我们的初始化类的路径。具体如图所示。
至此,我们需要的功能就已经写完了。这里我们测试一下。
测试如下;
当然实现上述功能,其实还有其他的方法,这块将spring的多个接口算是整合起来学习一下,换句话说就是写个笔记,用的时候好查一些。