360SDN.COM

Spring Framework 5 权威指南(13)

来源:程序员阮威  2017-09-11 13:24:37    评论:0点击:

这是一个Spring 5专题系列,其诞生的动机是:

1.介绍最新版本的Spring Framework;

2.介绍最系统化的Spring Framework;

3.介绍最佳实践的Spring Framework;

   7.Dependencies 

当不同的bean的生命周期不同时,依赖注入可能会产生一些问题。例如,singleton作用域的bean A依赖一个prototype作用域的bean B,由于容器只会实例化bean A一次,因此bean A只有一次初始化的机会,而不会在每一次的bean A需要时实例化一个新的bean B实例。

这个问题可以这样解决:

// a class that uses a statefulCommand-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 implementsApplicationContextAware {

 

        privateApplicationContext applicationContext;

 

        publicObject process(Map commandState) {

                // grab a new instance of the appropriate Command

               Command command = createCommand();

                // set the state on the (hopefully brand new) Commandinstance

                command.setState(commandState);

                return command.execute();

        }

 

        protectedCommand createCommand() {

                // notice the Spring API dependency!

                return this.applicationContext.getBean("command", Command.class);

        }

 

        publicvoid setApplicationContext(

                       ApplicationContext applicationContext) throws BeansException {

                this.applicationContext = applicationContext;

        }

}

这种方式的问题是,代码与Spring框架相耦合。SpringIoC容器支持方法注入,可以更好的解决这个问题。

查找方法注入,就是容器通过字节码生成技术(CGLIB)来动态生成覆盖了注入方法的子类,该方法返回被请求的bean实例。例如:

package fiona.apple;

 

// no more Spring imports!

 

public abstract class CommandManager{

 

        publicObject process(Object commandState) {

                // grab a new instance of the appropriate Commandinterface

               Command command = createCommand();

                // set the state on the (hopefully brand new) Commandinstance

               command.setState(commandState);

                return command.execute();

        }

 

        // okay... but where is the implementation of thismethod?

        protectedabstract Command createCommand();

}

查找方法需要遵循如下签名:

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

如果方法是抽象的,生成的子类将会实现这个方法,否则,生成的子类将会覆盖这个方法。

配置文件如下:

<!-- a stateful bean deployed as aprototype (non-singleton) -->

<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">

    <!-- inject dependencies here as required -->

</bean>

 

<!-- commandProcessor usesstatefulCommandHelper -->

<bean id="commandManager" class="fiona.apple.CommandManager">

    <lookup-method name="createCommand" bean="myCommand"/>

</bean>

// TODO 待补充,使用注解@Lookup

另一种解决不同生命周期bean的访问问题的办法是,注入一个bean的代理而不是bean本身:

<!-- a stateful bean deployed as aprototype (non-singleton) -->

<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">

    <!-- instructs the container to proxy the surrounding bean -->

    <aop:scoped-proxy/>

 

</bean>

 

<!-- a singleton-scoped bean injectedwith a proxy to the above bean -->

<bean id="commandManager" class="fiona.apple.CommandManager">

    <!--a reference to the proxied myCommond bean -->

    <property name="myCommond" ref="myCommand"/>

</bean>

默认情况,Spring容器为依赖生成基于CGLIB的代理,要生成基于JDK接口的代理,设置proxy-target-class属性为false即可。另一可选方案是ObjectFactory<T>/ObjectProvider<T>

比查找方法注入没那么常用的另一种方法注入,是任意方法替换,即用另一个方法实现替换bean的任意某个方法。例如:

public class MyValueCalculator{

 

        publicString computeValue(String input) {

                // some real code...

        }

 

        // some other methods...

 

}

新的方法实现代码如下:

/**

 *meant to be used to override the existing computeValue(String)

 *implementation in MyValueCalculator

 */

public class ReplacementComputeValueimplements MethodReplacer {

 

        publicObject reimplement(Object o, Method m, Object[] args) throwsThrowable {

                // get the input value, work with it, and return acomputed result

               String input = (String) args[0];

                ...

               return ...;

        }

}

配置文件如下:

<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">

    <!-- arbitrary method replacement -->

    <replaced-method name="computeValue" replacer="replacementComputeValue">

        <arg-type>String</arg-type>

    </replaced-method>

</bean>

 

<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>

阅读原文

为您推荐

友情链接 |九搜汽车网 |手机ok生活信息网|ok生活信息网|ok微生活
 Powered by www.360SDN.COM   京ICP备11022651号-4 © 2012-2016 版权