Spring Java 配置:仅指定类

问题描述 投票:0回答:4

我正在将一些基于 Xml 的 spring 配置转移到基于 Java 的配置。

以前,我有意识地根据具体情况将 Xml

<bean class='foo' />
声明与
@Component
映射混合在一起,作为记录非明显 bean 的一种方法。

一个典型的用例是,如果我声明将修改 spring 本身行为的 bean,我将显式声明它们,而不是让它们被发现,纯粹是为了提高配置文件的清晰度。

但是,这些豆子通常需要一定程度的

@Autowiring
。 如果我自己在 Java 配置中
new
启动 bean,我就负责执行此连接——这是毫无意义的。

是否有一个纯Java配置选项,显式地向Spring提供一个类,并让它管理实例化?

即:

给定课程:

public class MyFunkySpringBean implements InitializingBean {
    @Autowired Foo foo;
}

在 XML 配置中,这将被简单地声明为:

<bean class="MyFunkySpringBean" />

Java 语法中是否有等效的语法,我可以向 Spring 显式声明 bean 类,但不负责提供实际实例——将其留给 Spring。

例如:

@Configuration 
public class MyAppConfig {

    // Explictly provide the class, not the instance to Spring
    @Bean
    public MyFunkySpringBean funkyBean; // No instance -- it's up to Spring to build
}

要明确的是,我不想必须这样做:

@Configuration 
public class MyAppConfig {

    @Bean
    public MyFunkySpringBean funkyBean() {
         MyFunkySpringBean bean = new MyFunkySpringBean();
         bean.foo = new Foo();
         // other dependencies go here
         return bean;
    }

}

Spring 中是否存在这样的设施?

java spring
4个回答
3
投票

在较新版本的 Spring(从 4.2 开始),您可以使用

org.springframework.context.annotation.Import
例如

@Configuration
@Import(MyFunkySpringBean.class)
public class MyAppConfig {
   ... other config ...
}

3
投票

我从您的评论中了解到,您正在寻找一种如何在 Java 配置中实现构造函数自动装配(使用类型或注释自动装配)的方法...即相当于:

<bean class="com.example.Foo" autowire="constructor" />

我检查了Spring的源代码,找到了谁真正负责构造函数解析和自动装配,它是包私有类

ConstructorResolver
AbstractAutowireCapableBeanFactory
的组合。所以这是你自己无法使用的东西。

如果您真的想要在没有 XML 的情况下自动装配构造函数,您可以实现自己的

BeanDefinitionRegistryPostProcessor
并自己手动注册该 bean 定义:

public class CustomBeanDefinitionRegistrar implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Not interested in this method
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        registry.registerBeanDefinition("foo", BeanDefinitionBuilder.
                genericBeanDefinition(Foo.class).
                setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR).
                getBeanDefinition());
    }

}

这个bean工厂后处理器需要通过静态

@Bean
方法在你的
@Configuration
中注册:

@Configuration
public class MyAppConfig {

    public static BeanFactoryPostProcessor customBeanDefinitionRegistrar() {
        return new CustomBeanDefinitionRegistrar();
    }

}

我承认这有点“疯狂”,但这似乎是使用纯 Java 配置实现构造函数自动装配的唯一方法。


2
投票

您需要通知Spring一种发现将管理的bean的方法。您只有三种方法(还有第四种方法,但它更复杂并且还需要注释,解释为here):

  • 基于 XML 的配置:

    <bean id="foo" class="some.package.Foo" />
    
  • 注释配置:

    @Component
    public class Foo {
    }
    
  • 创建一个

    @Configuration
    类来显式声明 bean:

    @Configuration
    public class MyConfiguration {
        @Bean
        public Foo getFoo() {
            return new Foo(); //foo doesn't need any annotation at all.
        }
    }
    

据我所知,您可以使用 CDI 做一些类似的事情:

class MyConfiguration {

    @Produces
    Foo foo = new Foo();
}

或者从另一个容器注入资源,例如 JPA:

class MyConfiguration {

    //JPA will provide the object reference based on the persistence unit
    //CDI will just work as a by-pass to inject this reference in other beans
    @PersistenceContext //JPA annotation
    @Produces
    EntityManaged em;
}

但即使是 CDI 也需要一种方法来知道如何初始化 bean 或首先在哪里检索它。

参考:


1
投票

Spring 中是否存在这样的设施?

答案是有点,但不干净。

Spring 中的所有 bean 定义都依赖于

BeanDefinition
中的
ApplicationContext
对象。

使用 XML 配置,如

<bean class="com.example.SomeType">
</bean>

Spring 将生成一个具有该类类型并作为单例的

RootBeanDefinition
,但没有有关如何构造它的其他信息。相反,
ApplicationContext
将决定如何创建 bean。

与Java配置类似

@Bean
public com.example.SomeType someType() {
    return new com.example.SomeType();
}

Spring 将创建一个

RootBeanDefinition
但特别声明该 bean 应该从
@Configuration
bean 作为工厂 bean 生成,并且其
someType()
方法作为工厂方法生成。因此,
ApplicationContext
不必自行决定,它只需执行
BeanDefinition
告诉它的操作即可。

(未完成,我稍后会回来完成这个。)


您必须了解 XML 和 Java 配置是不同的,但尝试实现相同的目标。

当您像这样声明 XML

<bean>
元素时

<bean class="com.example.SomeType">
</bean>

您正在告诉 Spring 使用

SomeType
的无参构造函数来实例化 bean 类并创建一个 bean。

在 Java 中,等价的是

@Bean
public com.example.SomeType someType() {
    return new com.example.SomeType();
}

同样,

<bean class="com.example.SomeType">
    <constructor-arg type="java.lang.String" value="hello world"/>
    <property name="some" value="some value" />
</bean>

告诉 Spring 使用带有一个

String
类型参数和给定值的构造函数来实例化 bean 类。然后设置一些属性。等价的是

@Bean
public com.example.SomeType someType() {
    com.example.SomeType someType = new com.example.SomeType("hello world");
    someType.setSome("some value");
    return someType;
}

这些 bean 仍然会像其他 bean 一样成为自动装配的候选者。如果它们有

@Autowired
字段或方法,这些将被注入。

以上所有配置都准确地告诉 Spring 如何创建 bean。像这样的东西

@Bean
public MyFunkySpringBean funkyBean; // No instance -- it's up to Spring to build

除非设定了约定,否则实际上什么也没说。我认为该功能没有任何使用经典

@Bean
方法无法获得的优势。

© www.soinside.com 2019 - 2024. All rights reserved.