美文网首页
SpringFramework Core(三)

SpringFramework Core(三)

作者: 程序员文集 | 来源:发表于2019-12-20 23:07 被阅读0次

    方法注入

    在大多数应用场景中,容器中的大多数bean是 singletons。当单例Bean需要与另一个单例Bean协作或非单例Bean需要与另一个非单例Bean协作时,通常可以通过将一个Bean定义为另一个Bean的属性来处理依赖性。当bean的生命周期不同时会出现问题。

    假设单例bean A需要使用非单例(原型)bean B,也许在A的每个方法调用上都使用。容器仅创建一次单例bean A,因此只有一次机会来设置属性。每次需要一个容器时,容器都无法为bean A提供一个新的bean B实例。

    一个解决方案是放弃某些控制反转。你可以实现一个BeanAware容器通过实现ApplicationContextAware接口,并通过制作getBean("B")到容器调用请求(典型新)bean B实例的实例每次Bean A需要它。以下示例显示了此方法:

    // a class that uses a stateful Command-style class to perform some processing
    package fiona.apple;
    
    // Spring-API imports
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    
    public class CommandManager implements ApplicationContextAware {
    
        private ApplicationContext applicationContext;
    
        public Object process(Map commandState) {
            // grab a new instance of the appropriate Command
            Command command = createCommand();
            // set the state on the (hopefully brand new) Command instance
            command.setState(commandState);
            return command.execute();
        }
    
        protected Command createCommand() {
            // notice the Spring API dependency!
            return this.applicationContext.getBean("command", Command.class);
        }
    
        public void setApplicationContext(
                ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    }
    

    前面的内容是不理想的,因为业务代码知道并耦合到Spring框架。方法注入是Spring IoC容器的一项高级功能,使您可以干净地处理此用例。

    查找方法注入

    查找方法注入是容器覆盖容器管理的Bean上的方法并返回容器中另一个命名Bean的查找结果的能力。查找通常涉及原型bean,如上一节中所述。Spring框架通过使用从CGLIB库生成字节码来动态生成覆盖该方法的子类来实现此方法注入。

    为了使此动态子类起作用,Spring Bean容器子类的类也不能为final,并且要覆盖的方法也不能为final。

    对具有abstract方法的类进行单元测试需要您自己对该类进行子类化,并提供该abstract方法的存根实现。

    组件扫描也需要具体方法,这需要具体的类别。

    另一个关键限制是,查找方法不适用于工厂方法,尤其不适@Bean用于配置类中的方法,因为在这种情况下,容器不负责创建实例,因此无法在其上创建运行时生成的子类。

    对于CommandManager前面的代码片段中的类,Spring容器动态地覆盖该createCommand() 方法的实现。该CommandManager班没有任何Spring的依赖,因为返工例所示:

    package fiona.apple;
    
    // no more Spring imports!
    
    public abstract class CommandManager {
    
        public Object process(Object commandState) {
            // grab a new instance of the appropriate Command interface
            Command command = createCommand();
            // set the state on the (hopefully brand new) Command instance
            command.setState(commandState);
            return command.execute();
        }
    
        // okay... but where is the implementation of this method?
        protected abstract Command createCommand();
    }
    

    在包含要注入的方法的客户端类(CommandManager在本例中为)中,要注入的方法需要以下形式的签名:

    <public|protected> [abstract] <return-type> theMethodName(no-arguments);

    如果方法为abstract,则动态生成的子类将实现该方法。否则,动态生成的子类将覆盖原始类中定义的具体方法。考虑以下示例:

    <!-- a stateful bean deployed as a prototype (non-singleton) -->
    <bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">
        <!-- inject dependencies here as required -->
    </bean>
    
    <!-- commandProcessor uses statefulCommandHelper -->
    <bean id="commandManager" class="fiona.apple.CommandManager">
        <lookup-method name="createCommand" bean="myCommand"/>
    </bean>
    

    只要需要新的bean 实例,被标识为的bean 就会commandManager调用其自己的createCommand()方法myCommandmyCommand如果确实需要,您必须小心地将bean 部署为原型。如果是单例myCommand 则每次都返回Bean 的相同实例。

    另外,在基于注释的组件模型中,您可以通过@Lookup注释声明一个查找方法,如以下示例所示:

    public abstract class CommandManager {
    
        public Object process(Object commandState) {
            Command command = createCommand();
            command.setState(commandState);
            return command.execute();
        }
    
        @Lookup("myCommand")
        protected abstract Command createCommand();
    }
    

    或者,更惯用的是,您可以依赖于目标bean根据lookup方法的声明的返回类型来解析:

    public abstract class CommandManager {
    
        public Object process(Object commandState) {
            MyCommand command = createCommand();
            command.setState(commandState);
            return command.execute();
        }
    
        @Lookup
        protected abstract MyCommand createCommand();
    }
    

    相关文章

      网友评论

          本文标题:SpringFramework Core(三)

          本文链接:https://www.haomeiwen.com/subject/qnrwnctx.html