简体   繁体   English

是否可以在运行时将自己动态创建的对象注册为spring bean?

[英]Is it possible to register an object dynamically created by myself in runtime as a spring bean?

I need to use Spring AOP facility and would not like to make AspectJ integration in order to intercept a method call to an object which is not initially a spring bean. 我需要使用Spring AOP工具,并且不想进行AspectJ集成以拦截对最初不是spring bean的对象的方法调用。 The object is going to be created dynamically in runtime . 该对象将在运行时动态创建。 It's not possible for me to add a bean definition into ApplicationContext configuration file. 我不可能在ApplicationContext配置文件中添加bean定义。 So does spring provide such a facility? 那么春天提供这样的设施吗?

Yes, it's possible. 是的,这是可能的。 You could create a prototype scoped bean with @Bean and @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) in a @Configuration bean, which would act as a factory: 您可以在@Configuration bean中使用@Bean@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)创建一个原型范围的bean,它将充当工厂:

@Configuration
public class Factory {

    public static class A {

        private final int x;

        public A(int x) {
            this.x = x;
        }
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Autowired
    public A getA(int arg) {
        try {
            return A.class.getConstructor(int.class).newInstance(arg);
        } catch (Exception e) {
            throw new BeanCreationException("A" + arg, "Could not create instance of bean A", e);
        }
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public int getArg() {
        return (int) (Math.random() * 2 + 1);
    }

    @PostConstruct
    public void test() {

        int r1 = this.getArg();
        A a1 = this.getA(r1);
        System.out.println("a1.x = " + a1.x); // 1 or 2

        int r2 = this.getArg();
        A a2 = this.getA(r2);
        System.out.println("a2.x = " + a2.x); // 2 or 1, different to a1.x
    }
}

In method getA() , I could have created an instance of the A bean just with new A(arg) , however I created it dynamically, so that it's closer to your use case. 在方法getA() ,我可以使用new A(arg)创建A bean的实例,但是我动态创建它,以便它更接近您的用例。

Note that from Spring 4.x version onwards, you can use @Autowired to autowire the parameters of the bean to be returned by a @Bean method, meaning that those parameters can be other beans, even of primitive types. 请注意,从Spring 4.x版本开始,您可以使用@Autowired来自动装配由@Bean方法返回的bean的参数,这意味着这些参数可以是其他bean,甚至是原始类型。 That's why I made the argument of the A bean to also be a prototype scoped bean. 这就是为什么我让A bean的论点也成为原型范围的bean。

Then in the @PostConstruct method (which I'm using as a test), I get two instances of the int argument and two instances of the A bean, and assign each one of them to each instance of A . 然后在@PostConstruct方法(我用作测试)中,我获得了int参数的两个实例和A bean的两个实例,并将它们中的每一个分配给A每个实例。

If I hadn't used the @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) annotation, both getArg() and getA(arg) @Bean methods would have returned the same instance when invoked for the second time, as Spring's default scope for beans is ConfigurableBeanFactory.SCOPE_SINGLETON . 如果我没有使用@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)注释,则getArg()getA(arg) @Bean方法在第二次调用时都会返回相同的实例,因为Spring的bean默认范围是ConfigurableBeanFactory.SCOPE_SINGLETON If this is the behavior you expect, just remove the @Scope annotations. 如果这是您期望的行为,只需删除@Scope注释即可。

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

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