目前我直接在类上使用@CustomAnnotation,并使用BeanFactoryPostProcessor 来根据我的需要更改带注释的bean 的bean 定义。
@CustomAnnotation
public class MyBean implements IMybean{
}
@Configuration
public class MyConfiguration {
@Bean
public MyBean myBean(){
return new myBean();
}
}
我想做的是能够将@CustomAnnotation 放在配置文件的@Bean 方法上,如下所示:
public class MyBean implements IMybean{
}
@Configuration
public class MyConfiguration {
@Bean
@CustomAnnotation
public MyBean myBean(){
return new myBean();
}
}
从 BeanDefinition 我可以从 beanFactory 得到,我知道我可以得到工厂 bean 和创建 myBean 的工厂方法,并检查方法上是否有 @CustomAnnotation。
我不确定这样做是否会违反任何 spring 原则,或者这是否是常规做法。
我的初衷是工作。 但是我现在有另一个问题。 我无法使用我想要的类型 Autowiring 来 self 想要的工厂的 bean。 存在解决依赖关系的问题。 这是我用来尝试解决问题的测试代码。 test code on github
@Configuration
public class MainConfiguration implements BeanDefinitionRegistryPostProcessor, Ordered {
private SayenBeanDefinitionRegistryPostProcessor sayenBeanDefinitionRegistryPostProcessor = new SayenBeanDefinitionRegistryPostProcessor();
public int getOrder() {
return sayenBeanDefinitionRegistryPostProcessor.getOrder();
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
sayenBeanDefinitionRegistryPostProcessor.postProcessBeanFactory(beanFactory);
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
sayenBeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(beanFactory);
}
@Bean
public AutowiredBean autowiredBean() {
return new AutowiredBean();
}
@Bean
@Transform(type = MegaSuperKarim.class)
public Karim Karim() {
return new Karim();
}
@Bean
@Transform(type = SuperGuillaume.class)
public Guillaume Guillaume() {
return new Guillaume();
}
@Bean
public Yoann Yoann() {
return new Yoann();
}
@Bean
public Nicolas Nicolas() {
return new Nicolas();
}
@Bean
public BeanHolder beanHolder() {
return new BeanHolder();
}
}
public class TransformFactoryBean implements FactoryBean<Object> {
@Autowired
private AutowiredBean pouet;
private Class<?> objectType;
boolean singleton = true;
@Override
public Object getObject() throws Exception {
return objectType.getConstructor().newInstance();
}
@Override
public Class<?> getObjectType() {
return objectType;
}
@Override
public boolean isSingleton() {
return singleton;
}
public void setObjectType(Class<?> objectType) {
this.objectType = objectType;
}
public AutowiredBean getPouet() {
return pouet;
}
public void setSingleton(boolean singleton) {
this.singleton = singleton;
}
}
public class SayenBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, Ordered {
private static Logger logger = LoggerFactory.getLogger(MainConfiguration.class);
@Override
public int getOrder() {
return 0;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
logger.debug("rien");
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
//DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) beanFactory;
for (String originalBeanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition originalBeanDefinition = beanFactory.getBeanDefinition(originalBeanName);
logger.debug("original beanName=" + originalBeanName + ", " + originalBeanDefinition.toString());
if (originalBeanDefinition.isAbstract()) {
continue;
}
Transform sayenAnnotation = getMethodAnnotation(beanFactory, originalBeanDefinition);
/*if (sayenAnnotation == null) {
Class<?> originalBeanClass = beanFactory.getType(originalBeanName);
sayenAnnotation = AnnotationUtils.findAnnotation(originalBeanClass, Transform.class);
*/if (sayenAnnotation == null) {
continue;
}/*
}*/
Class<? extends Sayan> sayenClass = sayenAnnotation.type();
RootBeanDefinition sayenFactoryBeanDefinition = new RootBeanDefinition(TransformFactoryBean.class, 3/*Autowire.BY_TYPE.value()*/, true);
sayenFactoryBeanDefinition.getPropertyValues().add("objectType", sayenClass);
sayenFactoryBeanDefinition.getPropertyValues().add("singleton", true);
String factoryBeanName = originalBeanName;
logger.debug("remove beanName=" + originalBeanName + ", " + originalBeanDefinition.toString());
beanFactory.removeBeanDefinition(originalBeanName);
logger.debug("register beanName=" + factoryBeanName + ", " + sayenFactoryBeanDefinition.toString());
beanFactory.registerBeanDefinition(factoryBeanName, sayenFactoryBeanDefinition);
}
}
private Transform getMethodAnnotation(BeanDefinitionRegistry beanFactory, BeanDefinition originalBeanDefinition) {
String originalBeanFactoryBeanName = originalBeanDefinition.getFactoryBeanName();
String originalBeanFactoryMethodName = originalBeanDefinition.getFactoryMethodName();
if (originalBeanFactoryBeanName == null || originalBeanFactoryMethodName == null) {
return null;
}
Class<?> originalBeanFactoryBeanClass = ClassUtils.getUserClass(((DefaultListableBeanFactory)beanFactory).getType(originalBeanFactoryBeanName));
try {
Method method = originalBeanFactoryBeanClass.getMethod(originalBeanFactoryMethodName);
return AnnotationUtils.getAnnotation(method, Transform.class);
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
最佳答案
如果@CustomAnnotation 的唯一目的是影响类/bean 的创建方式,那么您采用了正确的方法。在这种情况下,注释的范围应该是在创建时(这是您在 @Configuration MyConfiguration 中将其移动到的位置)而不是类范围 (@Target(ElementType.TYPE))。
您实际上是在说 @CustomAnnotation 在创建后对 MyBean 没有进一步的用途,并且您的框架将永远不需要再次检查 MyBean 以获取此注释。这也意味着 @CustomAnnotation 可能用于创建其他 bean(MyBean2 等)。
关于java - 在@bean 工厂方法上使用自定义注解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34839323/