【问题标题】:Auto-cast Spring Beans自动转换 Spring Bean
【发布时间】:2010-10-23 04:01:56
【问题描述】:

有没有办法将 Spring bean 自动转换为应用程序上下文 XML 中定义的类?我想避免将有关 bean 的类型信息放在 2 个位置......在 xml 配置文件中以及作为强制转换的代码中。

例如,给定这个配置文件

<bean id="bean-name" class="SimpleSpringBean"  scope="prototype">
    <property name="myValue" value="simple value"></property>
</bean>

我可以调用ApplicationContext.getBean("bean-name") 以避免直接将返回类型转换为SimpleStringBean。我知道我也可以调用 ApplicationContext.getBean("bean-name", SimpleSpringBean.class) 来避免演员本身,但我仍然在 2 个地方有类型信息。

Spring 似乎可以获取类信息 (ApplicationContext.getType) 或通过 bean 本身获取类型,但没有程序员干预无法自动转换类型。

【问题讨论】:

  • 无论哪种方式,您都需要在两个地方提供类型信息,因为您需要声明变量的类型:SimpleStringBean var = ApplicationContext.getBean("bean-name"); 但这看起来像是在中断 java:getBean(String) 是什么类型返回?

标签: java spring casting javabeans


【解决方案1】:

答案是,如果可能的话,您根本不应该使用 ApplicationContext.getBean(),并忍受在引导代码中您必须使用的一个地方。 (通常,您永远不需要在应用程序的入口点之外使用 getBean()。)

此外,您所问的问题在 Java 语言中可能根本不可能。强制转换是一种编译时特性,结合了运行时检查。 getBean() 的返回类型必须在编译时知道。即使 Spring 可以确定对象的类型,它也无法在运行时更改自己的方法签名。

另一件事是,即使这是可能的,该功能也不会那么有用。因为 Spring AOP 是使用动态代理实现的,所以您几乎总是希望 Spring 向您提供 bean 实现的接口的实例(可能是 AOP 代理),而不是实现类的实例。

【讨论】:

    【解决方案2】:

    我同意 Sii,您应该尽可能避免调用 getBean。只需将您的 bean 连接到依赖它们的类。

    不过,如果你有一个单独的类来保存应用程序上下文,你可以提供一个包装器泛型方法,如下所示:

    class MyContextHolder{
        ApplicationContext appContext;
        ......
        @SuppressWarnings("unchecked")
        public static <T> T getBean(String beanName)
        {
            return (T)appContext.getBean(beanName);
        }
    }
    

    那么你就可以不用强制转换就调用它

    MyClass mc = MyContextHolder.getBean("myClassBean");
    

    【讨论】:

    • 为什么调用“getBean”被认为不好?您还能如何访问 Spring bean?
    • 一个。你遇到了铸造问题 b。您的代码依赖于 spring 框架 c。您可能会使用静态方法来访问应用程序上下文,这会降低您的代码可测试性 d. spring 框架的核心思想是依赖注入,如果 bean A 依赖于 bean B,spring 可以为你注入那个依赖,不需要调用 getBean
    • 基本上,如果你自己引导一个应用程序,你想要一个可以在 main 中使用 getBean() 的类,通过你配置的依赖项,Spring 构建你的整个具有依赖注入的对象图。关键是你的任何类都不知道或关心它们如何获得它们的依赖关系,如果你调用 getBean(),它们肯定会关心!
    • 关于 d,我完全理解我会使用 Spring 将 B 注入 A,但我仍然需要访问 A 作为某个点,对吗?我如何在不调用 getBean() 的情况下得到它?
    • 从技术上讲,您 / 真的 / 不需要访问 A。只要确保它没有使用 lazy="false" 提前初始化并定义一个将启动您的应用程序的 init 方法。
    【解决方案3】:

    我还使用的另一种方法是使用以下方法自动装配引导类:

    public class Main {
        @Autowired FooFacade foo;
        @Autowired BarFacade bar;
    
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("appCtx.xml");
            AutowireCapableBeanFactory bf = ctx.getAutowireCapableBeanFactory();
            Object main = bf.createBean(Main.class, 
                                        AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT,
                                        false);
            ((Main) main).run();
        }
    
        private void run() {
            foo.doBootstrapStuff();
            bar.doMoreBootstrapStuff();
        }
    }
    

    (代码从内存中完成。可能仅在您将 Spring 上下文配置为处理接线注释时才有效,在这种情况下,为 foobar 设置设置器应该可以工作。)

    【讨论】:

      【解决方案4】:

      getBean 无类型的主要原因是 Spring(最高版本 2.5.x)与 Java 1.4 的兼容性。 Spring 3.0 将放弃它,然后提供类型化的getBean 方法。

      尽管如此,您应该避免直接查找 bean 并尽可能减少其使用。

      【讨论】:

        【解决方案5】:

        如果我使用 Spring 作为我的应用程序广泛使用的对象工厂会怎样。 也就是说,而不是编写一堆已经继承或环绕的类 已知的 Java 类我只是决定将所有这些移动到一个 xml 文件中以减少 Java 代码行。这将意味着很多行 xml,但我不需要 我用 Spring 或 autowire 注入的骨架 Java 类。从而使线条 Java 代码更少。

        出于这个原因,我仍然是 Spring 的新手,我就像之前所说的那样 帖子使用了包含 getBeans() 的静态 Java 方法。

        我曾使用过 Spring,但它对我来说仍然是新的,所以请原谅我的问题。

        【讨论】:

          【解决方案6】:

          “因为 Spring AOP 是使用动态代理实现的,所以您几乎总是希望 Spring 向您提供 bean 实现的接口的实例(可能是 AOP 代理),而不是实现类的实例”

          所以没有办法使用 getBean() 来获取动态代理,那么如果没有接口并且它是一个独立的驱动程序类要执行,那么最好的做法是什么?

          【讨论】:

            猜你喜欢
            • 2017-06-09
            • 2018-01-05
            • 1970-01-01
            • 2016-09-27
            • 1970-01-01
            • 2017-07-22
            • 2012-11-15
            • 1970-01-01
            • 2010-10-29
            相关资源
            最近更新 更多