我创建了一个注释,用于创建使用环境中的值填充的ThreadPoolTaskExecutors.但是,当我自动装配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; }
我已经使用以下代码进行了测试:
Spring Boot类:
@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); } }
spring-boot-starter-parent 1.4.5.RELEASE的所有版本
我写了一个JUnit测试,检查值并通过.它唯一不起作用的是我在Spring Boot eureka应用程序中自动装配它.有什么我可以这样做,它不会自动装配代理bean?我搜索了文档并查看了所有相关的类,但我没有看到任何与它为代理相关的内容.另外,为什么在通过代理访问时会给出错误的值?
似乎您缺少用于注册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 }
翻译自:https://stackoverflow.com/questions/47360476/spring-programmatic-bean-autowired-as-proxy-instead-of-target