2017-11-17 384 views
8

我創建了一個註釋,用於創建用環境中的值填充的ThreadPoolTask​​Executors。但是,當我自動裝載這個bean時,它給了我一個代理並調用代理上的方法給出了錯誤的值。Spring編程bean自動裝配爲代理而不是目標

如果我手動訪問目標類,那麼我會得到正確的值。

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

我一直在抓我的頭一陣子,爲什麼我得到一個代理bean,但似乎無法弄清楚。

我使用註釋導入實現ImportBeanDefinitionRegistrar的註冊器類來註冊bean。註冊商代碼如下:

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; 
    } 

} 

註釋導入註冊地:

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

    String[] names(); 

    String[] rejectedHandler() default ThreadPoolPolicyHandlers.CALLER_RUNS_POLICY; 

} 

我已經用下面的代碼進行測試: 春天引導類:

@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); 
    } 
} 

從春天所有版本-boot-starter-parent 1.4.5.RELEASE

我寫了一個JUnit測試檢查值並通過。 唯一一次不起作用的是當我在Spring Boot eureka應用程序中自動裝入它時。有什麼我可以做的,它不會自動裝載代理bean?我查閱了文檔並查看了所有相關的類,但是我沒有看到與它爲什麼是代理相關的任何內容。另外,爲什麼當通過代理訪問時會產生不正確的值?

+1

你是什麼意思的「它給出了不正確的值」?你可以在代碼中分享注入和使用ThreadPoolTask​​Executor的代碼嗎? – Babl

+0

我只是在另一個春天的豆子裏自動裝配它。我打印出核心池大小,最大池大小和隊列容量的值。它返回默認值而不是創建時發送的屬性。 –

+0

我在問,因爲你的代碼完全適合我:)可能你可以共享Spring/Spring Boot的版本嗎? – Babl

回答

0

好像你缺少的代碼註冊實例您ImportBeanDefinitionRegistrar的(在你的例子是ExecutorEnumerationRegistrar) 因此,有兩種方式註冊ImportBeanDefinitionRegistrar直接使用@Import註釋或實現ImportSelector接口,它可以給你更多通用配置選項。

爲了您的情況,只需在Configuration類中添加@Import({ExecutorEnumerationRegistrar.class})即可。

@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); 
    } 
} 

,並只記得自動裝配的ThreadPoolTaskExecutor實例時使用的@Qualifier。看示例組件

@Component 
public class Component { 

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

    // you methods 
} 
+0

我已經通過我的ThreadPoolTask​​ExecutorCreator註釋導入了註冊商。我也爲此添加了代碼。我已經調試並測試了這段代碼很多次。它進入註冊商並創建bean。它也autowires它。問題是,它是自動裝配代理。 –

相關問題