简体   繁体   中英

How can I find all beans with custom annotation and inject it to Map of bean-manager?

I have some beans like this:

@MyAnnotation(type = TYPE1)
@Component
public class First implements Handler {

@MyAnnotation(type = TYPE2)
@Component
public class Second implements Handler {

@MyAnnotation(type = TYPE3)
@Component
public class Third implements Handler {

And I have controll bean for this beans:

@Component
public class BeanManager {

    private Map<Type, Handler> handlers = new HashMap<>();

    @Override
    public Handler getHandler(Type type) {
        Handler handler = map.get(type);
        if (handler == null)
            throw new IllegalArgumentException("Invalid handler type: " + type);
        return handler ;
    }
}

How can I fill handlers map in BeanManager when start server?

I know 3 ways for this:

1) fill map in costructor:

public BeanManager(First first, Second second, Third third){
  handlers.put(Type.TYPE1, first);
  handlers.put(Type.TYPE2, second);
  handlers.put(Type.TYPE3, third);
 }

I don't need annotations, but this approach is terrible and I brought it to complete the picture.

2) fill map in post costroctor( @PostConstruct ):

    @PostConstruct
    public void init(){
       Map<String, Object> beansWithAnnotation = context.getBeansWithAnnotation(MyAnnotation.class);
       //get type from annotation
       ...
      //add to map
      handlers.put(type, bean);
     }

In this solution BeanManager contains context and when I will use BeanManager in my code it will pull the context . I do not like this approach.

3) move move the search for annotations in bins to BeanPostProcessor and add setter to BeanManager :

@Component
public class MyAnnotationBeanPostProcessor implements BeanPostProcessor {

    private final BeanManager beanManager;

    public HandlerInAnnotationBeanPostProcessor(BeanManager beanManager) {
        this.beanManager = beanManager;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Annotation[] annotations = bean.getClass().getAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation instanceof MyAnnotation) {
                Type[] types = ((MyAnnotation) annotation).type();
                for (Type type: types) {
                    beanManager.setHandler(type, (Handler) bean);
                }
            }
        }
        return bean;
    }
}

But in this solution I do not like setHandler method .

Let change approche a little bit

@Component
public class BeanManager {

    private Map<Type, Handler> handlers = new HashMap<>();

    //haven't tested, just an idea : )
    @Autowired
    public void setHandler(List<Handler> handlersList) {
        for(Handler handler : handlers) {
            Type type = handler.getClass().getAnnotation(MyAnnotation.class).type();
            handlers.put(type, handler);
        }
    }
}

If you need more inspiration, check this out LINK

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM