我正在将一些基于 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 中是否存在这样的设施?
org.springframework.context.annotation.Import
例如
@Configuration
@Import(MyFunkySpringBean.class)
public class MyAppConfig {
... other config ...
}
我从您的评论中了解到,您正在寻找一种如何在 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 配置实现构造函数自动装配的唯一方法。
您需要通知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 或首先在哪里检索它。
参考:
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
方法无法获得的优势。