簡體   English   中英

在實例化之前自定義Spring bean自動裝配構造函數中的參數

[英]Customize arguments in spring bean autowired constructor, before instantiation

我需要實現的是與@RequestParam("foo")相同的行為,但是在一個REQUEST范圍內的bean的構造函數中,其他構造函數參數將正常進行自動裝配。

我想在構造函數中注入一個請求參數,就好像它是普通bean一樣,但是顯然沒有實際是spring bean。

例:

@Component
@RequestScope
public class RequestBean {    
    private final String filter;
    private final UserRepository userRepository;

    public RequestBean(@Param("filter") String filter, UserRepository userRepository) {
        this.filter = filter;
        this.userRepository = userRepository;
    }
    ...
}

我嘗試使用BeanFactoryPostProcessor,但必須在請求時而不是在bean定義時獲取需要注入的值。

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

        Stream.of(beanFactory.getBeanDefinitionNames())
                .map(name -> beanFactory.getBeanDefinition(name))
                .filter(def -> "request".equals(def.getScope()))
                .forEach(beanDefinition -> {
                    try {
                        System.out.println(beanDefinition);

                        for (Constructor<?> constructor : Class.forName(beanDefinition.getBeanClassName()).getConstructors()) {
                            for (Parameter parameter : constructor.getParameters()) {
                                Param param = parameter.getAnnotation(Param.class);
                                if(param != null) {
                                    String paramName = param.value(); // filter
                                    Object requestParameterValue = "request.getParameter('" + paramName + "')"; // bean creation time evaluated argument

                                    beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(
                                        new ConstructorArgumentValues.ValueHolder(requestParameterValue, parameter.getType().getName(), parameter.getName())
                                    );      
                                }
                            }
                        }
                    } catch (Exception ex) {
                        // whatever
                    }
                });
    }
}

對於對/index?filter=blue的請求,我希望“ blue”和userRepository已自動連線。

如果我嘗試使用固定值,那么它可以完美工作,該值和另一個bean可以正常自動接線。

我無法使用BeanPostProcessor因為必須在實例化(構造函數注入)之前獲取值

最后,我找到了實現自己想要的方法。

我定義了一個REQUEST范圍,以簡化獲取和轉換請求參數的過程。 由於在BeanFactoryPostProcessor中注冊了一個表達式(SprEL),因此將在創建時調用此bean。 將對表達式進行求值,並將返回值注入到帶注釋的參數中。

這會將動態表達式添加到構造函數參數中:

String name = param.value();
TypedStringValue dynamicValue = new TypedStringValue("#{@myBean.getParameter('"+name+"')}");
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(index, dynamicValue, constructorParameter.getType().getName());

這是在帶注釋的bean實例化之前由表達式調用的bean:

@Component
@RequestScope
class MyBean {
    final HttpServletRequest request;

    public MyBean(HttpServletRequest request) {
        this.request = request;
    }        

    public String getParameter(String name){
        // do something 
        return request.getParameter(name);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM