2017-11-17 110 views
8

Utworzono adnotację do tworzenia ThreadPoolTaskExecutors wypełnionych wartościami ze środowiska. Jednakże, gdy snuję komponent bean, daje mi to proxy, a wywoływanie metod na serwerze proxy daje złe wartości.Wiosenna automatyzacja fasoli autowyredowana jako proxy zamiast celu

Jeśli ręcznie uzyskaję dostęp do klasy docelowej, otrzymuję prawidłowe wartości.

Executor exec = (Executor) ((Advised) executor).getTargetSource().getTarget(); 
ThreadPoolTaskExecutor taskExec = (ThreadPoolTaskExecutor) exec; 

I zostały drapania moją głowę na chwilę teraz, dlaczego Dostaję fasoli proxy, ale nie potrafię zrozumieć.

Używam adnotacji do importowania mojej klasy rejestratora, która implementuje program ImportBeanDefinitionRegistrar w celu zarejestrowania komponentu bean. Kod rejestrator jest poniżej:

public class ExecutorEnumerationRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware { 

    public static final String CORE_POOL_SIZE = "corePoolSize"; 
    public static final String MAX_POOL_SIZE = "maxPoolSize"; 
    public static final String QUEUE_CAPACITY = "queueCapacity"; 
    public static final String THREAD_NAME_PREFIX = "threadNamePrefix"; 
    private static final String REJECTED_EXECUTION_HANDLER = "rejectedExecutionHandler"; 
    private static final String NAMES = "names"; 
    private static final String REJECTED_HANDLER = "rejectedHandler"; 
    private Environment env; 

    @Override 
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 
     Map<String, Object> attrs = importingClassMetadata.getAnnotationAttributes(ThreadPoolTaskExecutorCreator.class.getName(), true); 
     final String[] beanNames = (String[]) attrs.get(NAMES); 
     final String[] policyClass = (String[]) attrs.get(REJECTED_HANDLER); 
     for (int x = 0; x < beanNames.length; x++) { 
      createAndRegisterBean(beanNames[x], policyClass[x], registry); 
     } 
    } 

    private void createAndRegisterBean(String name, String policyClass, BeanDefinitionRegistry registry) { 
     GenericBeanDefinition bd = new GenericBeanDefinition(); 
     bd.setBeanClass(ThreadPoolTaskExecutor.class); 
     bd.setAutowireCandidate(true); 
     bd.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 
     MutablePropertyValues mpv = bd.getPropertyValues(); 
     populateProperties(mpv, name, policyClass); 
     registry.registerBeanDefinition(name, bd); 
    } 

    private void populateProperties(MutablePropertyValues mpv, String name, String policyClass) { 
     mpv.add(CORE_POOL_SIZE, Integer.valueOf(env.getProperty(name + "." + CORE_POOL_SIZE))); 
     mpv.add(MAX_POOL_SIZE, Integer.valueOf(env.getProperty(name + "." + MAX_POOL_SIZE))); 
     mpv.add(QUEUE_CAPACITY, Integer.valueOf(env.getProperty(name + "." + QUEUE_CAPACITY))); 
     try { 
      mpv.add(REJECTED_EXECUTION_HANDLER, Class.forName(policyClass).newInstance()); 
     } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { 
      e.printStackTrace(); 
     } 
     mpv.add(THREAD_NAME_PREFIX, name + "-"); 
    } 

    @Override 
    public void setEnvironment(Environment environment) { 
     env = environment; 
    } 

} 

Adnotacja importować sekretarz:

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.TYPE) 
@Documented 
@Import(ExecutorEnumerationRegistrar.class) 
public @interface ThreadPoolTaskExecutorCreator{ 

    String[] names(); 

    String[] rejectedHandler() default ThreadPoolPolicyHandlers.CALLER_RUNS_POLICY; 

} 

Ja testowałem z następującego kodu: wiosennym Boot Klasa:

@EnableDiscoveryClient 
@ComponentScan("my.test.classes") 
@ThreadPoolTaskExecutorCreator(names = {"testExecutor"}, rejectedHandler = ThreadPoolPolicyHandlers.DISCARD_POLICY) 
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, 
    SessionAutoConfiguration.class, 
    DataSourceTransactionManagerAutoConfiguration.class, 
    JpaRepositoriesAutoConfiguration.class, 
    JndiDataSourceAutoConfiguration.class, 
    JndiConnectionFactoryAutoConfiguration.class, 
    RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class}) 
public class TestBoot { 

    public static void main(String[] args) { 
     SpringApplication.run(TestBoot.class, args); 
    } 
} 

Wszystkie wersje z wiosną -boot-starter-parent 1.4.5.RELEASE

Napisałem test JUnit który sprawdza wartości i przechodzi. Jedynym momentem, w którym to nie działa, jest automatyczne wypowiadanie go w aplikacji Spring Boot eureka. Czy jest coś, co mogę zrobić, aby nie rozpowszechniać komponentu bean proxy? Przeszukałem dokumentację i przyjrzałem się wszystkim powiązanym klasom, ale nie widzę nic związanego z tym, dlaczego jest to proxy. Ponadto, dlaczego daje niepoprawne wartości, gdy dostęp za pośrednictwem serwera proxy?

+1

Co masz na myśli, mówiąc: "podaje niepoprawne wartości"? Czy możesz udostępnić kod do wtrysku i użycie 'ThreadPoolTaskExecutor' w swoim kodzie ...? – Babl

+0

Po prostu wypalam go w innym fasolku wiosennym. Wydrukuję wartości dla podstawowego rozmiaru puli, maksymalnego rozmiaru puli i pojemności kolejki. Zwraca wartości domyślne zamiast właściwości wysyłanych podczas tworzenia. –

+0

Pytam, ponieważ twój kod działa doskonale dla mnie :) Może chcesz udostępnić wersję Spring/Spring Boot co najmniej? – Babl

Odpowiedz

0

Wydaje brakuje kod rejestracji instancji Twojego ImportBeanDefinitionRegistrar (w przykładzie, który jest ExecutorEnumerationRegistrar) więc istnieją dwa sposoby, aby zarejestrować ImportBeanDefinitionRegistrar używają @Import adnotacji bezpośrednio lub implementują interfejs ImportSelector który może dać ci więcej ogólne opcje konfiguracji.

W przypadku Twojego przypadku wystarczy dodać @Import({ExecutorEnumerationRegistrar.class}) na klasie Configuration.

@EnableDiscoveryClient 
@ComponentScan("my.test.classes") 
@ThreadPoolTaskExecutorCreator(names = {"testExecutor"}, rejectedHandler = ThreadPoolPolicyHandlers.DISCARD_POLICY) 
// THIS IS REQUIRED 
@Import({ExecutorEnumerationRegistrar.class}) 
// See Above 
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, 
SessionAutoConfiguration.class, 
DataSourceTransactionManagerAutoConfiguration.class, 
JpaRepositoriesAutoConfiguration.class, 
JndiDataSourceAutoConfiguration.class, 
JndiConnectionFactoryAutoConfiguration.class, 
RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class}) 
public class TestBoot { 

    public static void main(String[] args) { 
     SpringApplication.run(TestBoot.class, args); 
    } 
} 

i po prostu pamiętać, aby używać @Qualifier gdy autowiring wystąpienie ThreadPoolTaskExecutor. Zobacz przykładowy składnik

@Component 
public class Component { 

    @Autowired 
    @Qualifier("testExecutor") 
    private ThreadPoolTaskExecutor exec; 

    // you methods 
} 
+0

Byłem już importowanie rejestratora za pomocą mojej adnotacji ThreadPoolTaskExecutorCreator. Dodałem również kod do tego. Debugowałem i testowałem ten kod wiele razy. Przechodzi do rejestratora i tworzy komponent bean. To także ją autodresuje. Problem polega na tym, że autowiruje proxy. –