2017-11-17 12 views
8

私は、環境から値を取り込んだThreadPoolTask​​Executorsを作成するためのアノテーションを作成しました。しかし、私がBeanをオートワイヤすると、私にプロキシが与えられ、プロキシのメソッドを呼び出すと間違った値が返されます。ターゲットではなくプロキシとしてオートプログラムされたSpringのプログラムビーン

ターゲットクラスに手動でアクセスすると、正しい値が得られます。

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

私は、プロキシBeanを取得しています理由として、今しばらくの間、私の頭を悩まされているが、それを把握するように見えることはできません。

私は、Beanを登録するためにImportBeanDefinitionRegistrarを実装するレジストラクラスをインポートするために注釈を使用しています。レジストラのコードは以下の通りです:

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

すべてのバージョン

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

} 

注釈がレジストラをインポートします-boot-starter-parent 1.4.5.RELEASE

私はJUnitテストを作成しました。それは値をチェックし、それがパスします。 それがうまくいけないのは、私がSpring Boot eurekaアプリケーションでautowireするときだけです。私はそれがプロキシビーンをautowireしないように何かできますか?私はドキュメンテーションを検索し、関連するすべてのクラスを見てきましたが、なぜそれがプロキシであるかに関係するものは何も表示されません。また、プロキシ経由でアクセスすると、なぜ不正な値を返すのでしょうか?

+1

"それは不正確な値を与える"とはどういう意味ですか?あなたのコードで 'ThreadPoolTask​​Executor'の注入と使用のためのコードを共有できますか? – Babl

+0

私は単に他の春の豆でそれをautowiringしています。私は、コアプールサイズ、最大プールサイズ、およびキュー容量の値を表示しています。作成時に送信されるプロパティではなく、デフォルト値が返されます。 –

+0

あなたのコードが私にとって完璧にうまくいくように私は尋ねています:)あなたは少なくともSpring/Spring Bootのバージョンを共有することができますか? – Babl

答えて

0

のでImportBeanDefinitionRegistrarが直接@Import注釈を使用するか、より多くのあなたを与えることができImportSelectorインタフェースを実装登録するには2つの方法がありますが、 (ExecutorEnumerationRegistrarであるあなたの例では)あなたのImportBeanDefinitionRegistrarのインスタンスを登録するためのコードが欠落しているようです一般的な設定オプション

あなたの場合は、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を作成します。それはまたそれをautowire。問題は、それがプロキシをautowiringしていることです。 –

関連する問題