使用spring工厂方法(FactoryBean)模式动态创建bean

有时候自己需要动态创建一些bean,并托管给spring进行注入使用,比如Mybatis的Mapper。在什么时机去创建Mapper接口的实例(动态代理),并能让spring自动注入给依赖依赖方,spring的工厂方法FactoryBean就可以解决(不是BeanFactory)。

下面以 Retrofit 为例简单说明,自己实现了接口定义(RetrofitService)的HTTP-RPC调用,然后托管给spring注入给依赖方,但接口RetrofitService的实力是由retrofit动态创建(动态代理)

先声明一个 FactoryBean的实现

public class ServiceFactoryBean implements FactoryBean {


    private Retrofit retrofit;

    private Class serviceClass;

    public void setServiceClass(Class serviceClass){
        this.serviceClass = serviceClass;
    }

    public void setRetrofit(Retrofit retrofit) {
        this.retrofit = retrofit;
    }

    @Override
    public Object getObject() throws Exception {

        return retrofit.create(this.serviceClass);
    }

    @Override
    public Class getObjectType() {
        return serviceClass;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

在spring进行bean定义处理的时候就把类B的bean在spring中注册一下(实现接口BeanDefinitionRegistryPostProcessor)

@Configuration
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Autowired
    BeanNameGenerator beanNameGenerator;

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        logger.info("Invoke Metho postProcessBeanDefinitionRegistry");

        Reflections reflections = new Reflections("com.myapp.api.service");
        Retrofit retrofit = retrofit();
        Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(RetrofitService.class);
        for (Class<?> serviceClass : annotated) {
            for(Annotation annotation : serviceClass.getAnnotations()){
                if (annotation instanceof RetrofitService){//自定义注解RetrofitService,都需要通过retrofit创建bean
                    RootBeanDefinition beanDefinition = new RootBeanDefinition();
                    beanDefinition.setBeanClass(ServiceFactoryBean.class);
                    beanDefinition.setLazyInit(true);
                    beanDefinition.getPropertyValues().addPropertyValue("retrofit", retrofit);
                    beanDefinition.getPropertyValues().addPropertyValue("serviceClass", serviceClass);
                    String beanName = this.beanNameGenerator.generateBeanName(beanDefinition, registry);
                    registry.registerBeanDefinition(beanName, beanDefinition);
                }
            }
        }
    }

    public Retrofit retrofit() {

        final String basic = Base64.encodeToString(token.getBytes());

        final OkHttpClient okHttpClient = new OkHttpClient();
        okHttpClient.setReadTimeout(60, TimeUnit.SECONDS);
        okHttpClient.setConnectTimeout(60, TimeUnit.SECONDS);

        okHttpClient.interceptors().add(new Interceptor() {
            @Override
            public Response intercept(Interceptor.Chain chain) throws IOException {
                Request original = chain.request();

                Request.Builder requestBuilder = original.newBuilder()
                        .header("Authorization", basic)
                        .method(original.method(), original.body());

                Request request = requestBuilder.build();
                return chain.proceed(request);
            }
        });

        return new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(JacksonConverterFactory.create())
                .client(okHttpClient)
                .build();
    }

}

如自己定义的类B接口

@RetrofitService
public interface UserService {
    @POST("/user/register")
    Call<Object> register(@Body User user);
}

为什么要用BeanDefinitionRegistryPostProcessor,可以看看org.springframework.context.support.AbstractApplicationContext#refresh

BeanFactory 它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

FactoryBean 作用是产生其他bean实例getObjectType()

到此完成,需要用户的地方直接使用按照驼峰命名引用或使用注解Autowired

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值