简体   繁体   English

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

[英]How to create a request scoped bean at runtime with spring

I have a spring application and want to create a bean at runtime per request to inject it into another class, just like @Producer for CDI. 我有一个spring应用程序,并希望在运行时根据请求创建一个bean,将其注入另一个类,就像@Producer for CDI一样。

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 UserDetails instance 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

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 UserFactory never called? 为什么从不调用UserFactory

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 UserDetails through reflection, it will not inject your scoped bean. 这将导致spring尝试通过反射创建UserDetails的新实例,它不会注入您的scoped bean。 Hence it complains about the fact you need a default no-args constructor. 因此,它抱怨你需要一个默认的无参数构造函数。

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 UserDetails is a scoped proxy and when used will either use the already present object or create a new one based on the @Bean method. 我们的想法是UserDetails是一个作用域代理,使用时将使用已存在的对象或基于@Bean方法创建一个新对象。

Additonally, the @Scope annotation in the UserFactory has to be modified as follows in order to work: 另外, UserFactory@Scope注释必须按如下方式修改才能工作:

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

You're trying to inject a request scoped bean on a singleton bean. 您正在尝试在单例bean上注入请求范围的bean。 You need to use a proxy for the UserDetails 您需要为UserDetails使用代理

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

You need a no arguments constructor in class UserDetails . UserDetails类中需要一个无参数的构造函数。

public class UserDetails {

    private String name;

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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