Spring --- IOC II

承接前一篇Spring --- IOC,继续IOC的介绍

6) 方法注入
   首先说说方法注入的使用场景:
   当一个singleton bean A 在每次方法调用的时候都需要一个non-singleton bean B,此时就会产生这样一个问题,因为A为singleton,所以容器只会创建一次A,那么也只有一次机会来创建A的属性,无论你是通过setter还是constructor方式注入Bean B,Bean B也只能被初始化一次,而实际需求是我们调用每个方法的时候又都需要一个新的Bean B实例。而方法注入就是解决这个问题的方法之一。具体看看如何实现:

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();
}


<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="command" class="fiona.apple.AsyncCommand" scope="prototype">
  <!-- 具体配置这里省略 -->
</bean>
<!-- commandProcessor uses statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager">
  <lookup-method name="createCommand" bean="command"/>
</bean>


    Spring 会自动通过CGLIB动态生成一个子类,继承CommandManager ,并重写原有的createCommand()方法,再根据配置信息createCommand()方法会自动返回一个command bean。

    还有一种任意方法的替代方式,不过这不太常用,这里写出来仅供参考吧:
public class MyValueCalculator {
  public String computeValue(String input) {
    // some real code...
  }
  // some other methods...
}
/** meant to be used to override the existing computeValue(String)
implementation in MyValueCalculator
*/
public class ReplacementComputeValue implements MethodReplacer {
  public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
    // get the input value, work with it, and return a computed 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"/>

  MyValueCalculator 的computeValue方法将被ReplacementComputeValue中的reimplement方法中对应的逻辑所取代。

7) Bean scopes
    spring的Bean scopes一共有五种: singleton、prototype、request、session、global session,大致可以分为两类:
    第一类是singleton和prototype, singleton表示单件模式,prototype在每次请求该Bean时会新建一个实例。其中singleton是spring bean的缺省值。
    第二类是request,session,global session。它们是专用于Web应用程序上下文里的Bean的范围的。要使用这3个属性值之前,我们需要先在web应用的web.xml文件中添加如下配置:
   对于spring2.4+的版本:
<web-app>
...
<listener>
  <listener-class>
    org.springframework.web.context.request.RequestContextListener
  </listener-class>
</listener>
...
</web-app>

   而对于spring2.3及以下版本,添加的配置应为:
<web-app>
...
  <filter>
    <filter-name>requestContextFilter</filter-name>
    <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>requestContextFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
...
</web-app>

    request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效。
    session作用域表示该次HTTP请求会产生一个新的bean,同时该beand的生命周期与当前HTTP session一样。
    global session与session类似,只是它的生命周期与global portlet session一致。(要理解global session需要知道portlet的概念,为了突出重点,这里就不对portlet作进一步的说明了。 http://www.lhjy.net/RecruiStu/JSJ/200512/20350.html

    最后,当一个singleton的bean需要关联一个request session或global session 的时候,因为singleton的bean只会实例化一次,所以我们需要一个代理来实现userPreference的scope
   
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
  <aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.foo.UserManager">
  <property name="userPreferences" ref="userPreferences"/>
</bean>


8) bean的生命周期
  bean的初始化:
  1' 声明初始化函数:
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {
  public void init() {
    // do some initialization work
  }
}

 
  2' 继承InitializingBean 接口:
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements InitializingBean {
  public void afterPropertiesSet() {
    // do some initialization work
  }
}

  bean的销毁:
  1'声明销毁函数:
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean {
  public void cleanup() {
    // do some destruction work (like releasing pooled connections)
  }
}


  2' 继承DisposableBean接口:
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements DisposableBean {
  public void destroy() {
    // do some destruction work (like releasing pooled connections)
  }
}

  在Spring启动和关闭时被调用的callback方法:
  首先是类的层次关系:
public interface Lifecycle {
  void start();
  void stop();
  boolean isRunning();
}
public interface LifecycleProcessor extends Lifecycle {
  void onRefresh();
  void onClose();
}
public interface Phased {
  int getPhase();
}
public interface SmartLifecycle extends Lifecycle, Phased {
  boolean isAutoStartup();
  void stop(Runnable callback);
}

  当ApplicationContext启动或停止时,它会通过LifecycleProcessor来与所有声明的bean的周期做状态更新。而SmartLifecycle的用法如下:
public class LfCycleBean1 implements SmartLifecycle{
    protected static final Log log = LogFactory.getLog(LfCycleBean1.class);
    private boolean isRunning = false;
    @Override
    public boolean isAutoStartup() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public void stop(Runnable arg0) {
        arg0.run();
        isRunning = false;
        log.info("stop Runnable");   
    }

    @Override
    public boolean isRunning() {
        // TODO Auto-generated method stub
        return isRunning;
    }
    @Override
    public void start() {
        isRunning = true;
        log.info("start ");    
    }
    @Override
    public void stop() {
        isRunning = false;
        log.info("stop");   
    }
    @Override
    public int getPhase() {      
        return -1;
    }
}

<bean id="LfCycleBean1" class="com.test.spring.lifecycle.LfCycleBean1" />

isAutoStartup返回的值决定是否在Spring启动的时候运行start方法,ture的话则运行.
isRunning返回的值决定是否在Spring关闭的时候运行stop(Runnable arg0)方法,ture的话则运行.
getPhase返回的值决定启动的顺序,值越小越先启动,越后关闭,用于调整在有多个这样的bean的时候,这些bean之间启动的优先级.

  非web环境下,需要设置ctx.registerShutdownHook(),Spring容器关闭的时候才会调用stop方法.
AbstractApplicationContext ctx
= new ClassPathXmlApplicationContext(new String []{"beans.xml"});
ctx.registerShutdownHook(); 

你可能感兴趣的:(java,spring,IOC)