Spring Java配置:仅指定类

时间:2014-04-26 15:57:45

标签: java spring

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

以前,我会根据具体情况有意识地将Xml <bean class='foo' />声明与@Component映射混合,作为记录非明显bean的方法。

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

但是,这些bean通常需要@Autowiring度。如果我在Java配置中自己new bean,我就会负责执行这种连接 - 这是毫无意义的。

是否有纯Java配置选项明确地将类提供给Spring,并让它管理实例化?

即:

鉴于课程:

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

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

<bean class="MyFunkySpringBean" />

Java语法中是否存在等价物,我可以将bean显式声明为Spring,但不负责提供实际实例 - 将其留给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中?

4 个答案:

答案 0 :(得分:3)

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

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

我已经检查了Spring的源代码,找到了实际负责构造函数解析和自动装配的人,它是包私有类ConstructorResolverAbstractAutowireCapableBeanFactory的组合。所以这是你自己无法使用的东西。

如果你真的想在没有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中的静态@Configuration方法注册此bean工厂后处理器:

@Configuration
public class MyAppConfig {

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

}

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

答案 1 :(得分:2)

您需要通知Spring一种方法来发现将要管理的bean。你只有三种方式(其中第四种方式,但它更复杂,也需要注释,解释here):

  • 基于XML的配置:

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

    @Component
    public class Foo {
    }
    
  • 创建一个明确声明bean的@Configuration类:

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

AFAIK您可以使用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或首先检索它。

参考:

答案 2 :(得分: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,但具体说明应该从@Configuration bean生成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仍然可以像其他任何人一样自动装配。如果他们有@Autowired个字段或方法,则会注入这些字段或方法。

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

@Bean
public MyFunkySpringBean funkyBean; // No instance -- it's up to Spring to build
除非设置了约定,否则

实际上没有说什么。我认为使用经典@Bean方法无法获得该功能的任何优势。

答案 3 :(得分:1)

在较新的Spring版本(从4.2版本开始)中,您可以使用org.springframework.context.annotation.Import例如

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