2013-12-02 2 views
0

Есть ли простой способ весной (без XML) иметь интерфейс, подключенный к обработчику вызова? В настоящее время я должен сделать что-то вроде этого:Внедрение службы через InvocationHandler

@Inject 
private ServiceProxyCreator services; 

private MyServiceInterface service; 

private MyServiceInterface getService() { 
    if (service == null) 
     service = services.createProxy(MyServiceInterface.class); 

    return service; 
} 

Где #createProxy просто реализация чего-то вроде этого:

@SuppressWarnings("unchecked") 
public <T> T createProxy(Class<T> type) { 
    JobRpcHandler handler = new JobRpcHandler(); 
    handler.setServiceName(type.getSimpleName()); 
    return (T) Proxy.newProxyInstance(
     type.getClassLoader(), new Class[]{type}, handler); 
} 

Но при всей этой функциональности DI весной кажется, что я должен быть в состоянии чтобы сделать все это автоматически, так что я могу просто сделать следующее:

@Inject 
private MyService service; 

с введением настроенного каким-то образом, что я не знаю, чтобы создать прокси-сервер за кулисами witho ut, чтобы вызвать #createProxy.

Любые предложения по более элегантному подходу?

ответ

0

Посмотрите на FactoryBean. Вы можете написать свой собственный таким образом:

public class ServiceProxyFactoryBean implements FactoryBean<Object> 
    private Class<T> type; 

    public DutySetFactoryBean(Class<?> type) { 
     this.type = type; 
    } 

    @Override 
    public synchronized Object getObject() { 
     JobRpcHandler handler = new JobRpcHandler(); 
     handler.setServiceName(type.getSimpleName()); 
     return Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, handler); 
    } 

    @Override 
    public Class<?> getObjectType() { 
     return type; 
    } 

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

и использовать его в конфигурационном файле:

<bean class="package.name.ServiceProxyFactoryBean"> 
    <constructor-arg> 
    <value type="java.lang.Class">package.name.MyServiceInterface</value> 
    </constructor-arg> 
</bean> 

или, используя конфигурацию Java, таким образом:

@Bean 
public ServiceProxyFactoryBean myServiceFactoryBean() { 
    return new ServiceProxyFactoryBean(MyServiceInterface.class); 
} 

@Bean 
public MyServiceInterface myService() { 
    return (MyServiceInterface)sessionFactoryBean().getObject(); 
} 

Если вы хотите автоматически создавать прокси для всех аннотированных интерфейсов в пути к классам, вы можете определить свой собственный BeanDefinitionRegistryPostProcessor. Здесь вы должны сканировать с ResourceLoader путем к классам, используя следующую схему:

MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); 
Resource[] resources = patternResolver.getResources(
     "classpath*:" + packageName.replace('.', '/') + "/**/*.class"); 
for (Resource resource : resources) { 
    MetadataReader reader = metadataReaderFactory.getMetadataReader(resource); 
    if (!reader.getAnnotationMetadata().isAnnotated(
      MyProxyAnnotation.class.getName())) { 
     continue; 
    } 
    Class<?> cls = Class.forName(reader.getClassMetadata().getClassName(), true, 
      resourceLoader.getClassLoader()); 
    String factoryBeanName = createNewName(); 
    BeanDefinitionBuilder bdb = BeanDefinitionBuilder.genericBeanDefinition(
      ServiceProxyFactoryBean.class); 
    bdb.addConstructorArgValue(cls); 
    registry.registerBeanDefinition(factoryBeanName, bdb.getBeanDefinition()); 
    bdb = BeanDefinitionBuilder.genericBeanDefinition(cls); 
    bdb.setFactoryBean(factoryBeanName, "getBean"); 
    registry.registerBeanDefinition(createNewName(), bdb.getBeanDefinition()); 
} 

Теперь для всех интерфейсов, снабженных MyProxyAnnotation, у вас есть прокси-сервер, который можно впрыснуть в ваши бобы. Например:

@MyProxyAnnotation 
public interface MyServiceInterface { 
    void foo(); 
} 

И

@Component 
public class MyBean { 
    @Autowired 
    private MyServiceInterface myService; 
} 

Это все. Конфигурация не требуется.

Я не уверен, что этот код работает или даже компилируется. Это не окончательное решение, просто общий путь, к которому вы должны двигаться. Поэтому вам следует немного исследовать и отлаживать.

+0

Я даже не уверен, почему я хочу использовать FactoryBean. Я имею в виду, если мне нужно создать метод Bean в одном из моих классов конфигурации для каждого класса, тогда я не могу просто создать прокси-сервер в методе myService Bean? Что мне делать с фабрикой? Я надеялся, что есть способ сделать это, не создавая метод bean для КАЖДОГО удаленного интерфейса. Но я также не мог полностью понять ваш пример. –

+0

@ user1888440, если я понял вас, вы не хотите регистрировать эти бобы вручную? Очень похоже на стереотипы (@Component и другие). Таким образом, вы можете увеличить весну, чтобы сделать это за вас. Я отредактировал свой ответ и добавил там описание того, как вы должны это делать. –

Смежные вопросы