使用spring工廠方法(FactoryBean)模式動態建立bean
阿新 • • 發佈:2019-01-06
有時候自己需要動態建立一些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