java 如何在运行时使用 spring 创建请求范围的 bean

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36031325/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 00:54:08  来源:igfitidea点击:

How to create a request scoped bean at runtime with spring

javaspring

提问by flash

I have a spring application and want to create a bean at runtime per request to inject it into another class, just like @Producerfor CDI.

我有一个 spring 应用程序,想在每个请求运行时创建一个 bean 以将其注入另一个类,就像@ProducerCDI 一样。

My bean is just a simple POJO:

我的 bean 只是一个简单的 POJO:

public class UserDetails {

    private String name;

    // getter / setter ... 

    public UserDetails(String name) {
        this.name = name;
    }
}

My producer class looks like this:

我的生产者类看起来像这样:

@Configuration
public class UserFactory {

    @Bean
    @Scope("request")
    public UserDetails createUserDetails() {
        // this method should be called on every request
        String name = SecurityContextHolder.getContext()
                        .getAuthentication().getPrincipal(); // get some user details, just an example (I am aware of Principal)

        // construct a complex user details object here
        return new UserDetails(name)
    }
}

And this is the class where the UserDetailsinstance should be injected:

这是UserDetails应该注入实例的类:

@RestController
@RequestMapping(value = "/api/something")
public class MyResource {

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public List<String> getSomething(UserDetails userDetails) {
        // the userdetails should be injected here per request, some annotations missing?

        // do something
    }
}

The problem is that Spring complains at runtime about no default constructor (of course).

问题是 Spring 在运行时抱怨没有默认构造函数(当然)。

Failed to instantiate [UserDetails]: No default constructor found

Failed to instantiate [UserDetails]: No default constructor found

But this is intended and I want to call my own factory to let it handle the Instantiation.

但这是有意的,我想调用我自己的工厂让它处理实例化。

How can I achieve this? Why is UserFactorynever called?

我怎样才能做到这一点?为什么UserFactory从不调用?

回答by M. Deinum

Basically you aren't using your scoped proxy. You cannot inject a scoped proxy into a method, you have to inject it into your controller.

基本上你没有使用你的范围代理。您不能将作用域代理注入到方法中,而必须将其注入到控制器中。

public List<String> getSomething(UserDetails userDetails) { ... }

This will lead to spring trying to create a new instance of UserDetailsthrough reflection, it will not inject your scoped bean. Hence it complains about the fact you need a default no-args constructor.

这将导致 spring 试图UserDetails通过反射创建一个新实例,它不会注入您的作用域 bean。因此它抱怨你需要一个默认的无参数构造函数。

Instead what you should do is wire the dependency into your controller instead of the controller method.

相反,您应该做的是将依赖项连接到您的控制器而不是控制器方法中。

@RestController
@RequestMapping(value = "/api/something")
public class MyResource {

    @Autowired
    private UserDetails userDetails;

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public List<String> getSomething() {
        // the userdetails should be injected here per request, some annotations missing?

        // do something
    }
}

The idea is that the UserDetailsis a scoped proxy and when used will either use the already present object or create a new one based on the @Beanmethod.

这个想法是UserDetails一个作用域代理,使用时将使用已经存在的对象或基于该@Bean方法创建一个新对象。

Additonally, the @Scopeannotation in the UserFactoryhas to be modified as follows in order to work:

此外,必须按如下方式修改 中的@Scope注释UserFactory才能工作:

@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) 

回答by isah

You're trying to inject a request scoped bean on a singleton bean. You need to use a proxy for the UserDetails

您正在尝试在单例 bean 上注入一个请求范围的 bean。您需要使用代理UserDetails

@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES) 

回答by Jens

You need a no arguments constructor in class UserDetails.

您需要在 class 中使用无参数构造函数UserDetails

public class UserDetails {

    private String name;

    // getter / setter ... 
    public UserDetails() {
    }

    public UserDetails(String name) {
        this.name = name;
    }
}