Spring4

    方法注入主要是用在Singleton的Object中使用非Singleton的Bean时,通过lookup-method的那个方法来取得非Singleton的Bean。一般用的不多,在用这种定义之前最好想明白你的需求。

1 使用Java代码实现方法注入

1.1 用法示例

1// a class that uses a stateful Command-style class to perform some processing 2package fiona.apple; 3 4// Spring-API imports 5import org.springframework.beans.BeansException; 6import org.springframework.context.ApplicationContext; 7import org.springframework.context.ApplicationContextAware; 8 9public class CommandManager implements ApplicationContextAware { 10 11 private ApplicationContext applicationContext; 12 13 public Object process(Map commandState) { 14 // grab a new instance of the appropriate Command 15 Command command = createCommand(); 16 // set the state on the (hopefully brand new) Command instance 17 command.setState(commandState); 18 return command.execute(); 19 } 20 21 protected Command createCommand() { 22 // notice the Spring API dependency! 23 return this.applicationContext.getBean("command", Command.class); 24 } 25 26 public void setApplicationContext( 27 ApplicationContext applicationContext) throws BeansException { 28 this.applicationContext = applicationContext; 29 } 30}

    上面的例子并没有达到期望的效果,因为业务代码和Spring框架产生的耦合。方法注入,作为Spring Ioc容器的高级特性,可以以一种 干净的方法来处理这种情况。

1.2 代码示例

1.2.1 准备Bean

1package com.ws.edu.spring; 2 3public class Game { 4} 5 6 7package com.ws.edu.spring; 8 9import org.springframework.beans.BeansException; 10import org.springframework.context.ApplicationContext; 11import org.springframework.context.ApplicationContextAware; 12 13public class Person implements ApplicationContextAware{ 14 private ApplicationContext applicationContext; 15 16 @Override 17 public void setApplicationContext(ApplicationContext applicationContext) 18 throws BeansException { 19 this.applicationContext = applicationContext; 20 } 21 22 private Game createGame(){ 23 return applicationContext.getBean(Game.class); 24 } 25 26 public void playGame(){ 27 Game game = this.createGame(); 28 System.out.println("playing game:"+game); 29 } 30}

1.2.2 配置XML

1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd" default-lazy-init="true"> 6 <bean id="person" class="com.ws.edu.spring.Person"/> 7 <bean id="game" class="com.ws.edu.spring.Game" scope="prototype"/> 8</beans>

1.2.3 配置启动类

1package com.ws.edu.spring; 2 3import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5public class App { 6 @SuppressWarnings("resource") 7 public static void main(String[] args) { 8 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); 9 Person person = context.getBean(Person.class); 10 person.playGame(); 11 } 12}

1.2.4 输出结果

2 使用Lookup实现方法注入

   Lookup方法注入的内部机制是Spring利用了CGLIB库在运行时生成二进制代码的功能,通过动态创建Lookup方法bean的子类从而达到复写Lookup方法的目的。

    为了使动态子类起作用,Spring容器要子类化的类不能是final,并且需要复写的方法也不能是final。同样的,要测试一个包含 抽象方法的类也稍微有些不同,你需要子集编写它的子类提供该抽象方法的实现。最后,作为方法注入目标的bean不能是序列化的。 在Spring 3.2之后再也没必要添加CGLIB到classpath,因为CGLIB的类打包在了org.springframework下并且在Spring核心JAR中有所描述。 这样做既方便,又避免了与其他使用了不同版本CGLIB的项目的冲突。

2.1 用法示例

1package fiona.apple; 2 3// no more Spring imports! 4 5public abstract class CommandManager { 6 7 public Object process(Object commandState) { 8 // grab a new instance of the appropriate Command interface 9 Command command = createCommand(); 10 // set the state on the (hopefully brand new) Command instance 11 command.setState(commandState); 12 return command.execute(); 13 } 14 15 // okay... but where is the implementation of this method? 16 protected abstract Command createCommand(); 17}

    在包含被注入方法的客户类中(这个例子中是CommandManager),此方法的定义需要按以下形式进行:

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

    public|protected要求方法必须是可以被子类重写和调用的;

    abstract可选,如果是抽象方法,CGLIB的动态代理类就会实现这个方法,如果不是抽象方法,就会覆盖这个方法,所以没什么影响;

    return-type就是non-singleton-bean的类型咯,当然可以是它的父类或者接口。

    no-arguments不允许有参数。 

 如果方法是抽象,动态生成的子类会实现该方法。沟则,动态生成的子类会覆盖类里的具体方法。譬如:    

1<!-- a stateful bean deployed as a prototype (non-singleton) --> 2<bean id="command" class="fiona.apple.AsyncCommand" scope="prototype"> 3 <!-- inject dependencies here as required --> 4</bean> 5 6<!-- commandProcessor uses statefulCommandHelper --> 7<bean id="commandManager" class="fiona.apple.CommandManager"> 8 <lookup-method name="createCommand" bean="command"/> 9</bean>

    标识为_commandManager_的bean在需要一个新的_command_ bean实例时会调用createCommand()方法。你必须将`command`bean部署为 原型(prototype)类型,如果这是实际需要的话。如果部署为singleton。那么每次将返回相同的 `command`bean。

2.2 代码示例

2.2.1 准备Bean

1package com.ws.edu.spring; 2 3public class Game { 4} 5 6 7package com.ws.edu.spring; 8 9public class Person{ 10 11 public Game createGame(){ 12 return null; 13 } 14 15 public void playGame(){ 16 Game game = this.createGame(); 17 System.out.println("playing game:"+game); 18 } 19}

2.2.2 配置Xml

1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd" default-lazy-init="true"> 6 <bean id="person" class="com.ws.edu.spring.Person"> 7 <lookup-method bean="game" name="createGame"/> 8 </bean> 9 <bean id="game" class="com.ws.edu.spring.Game" scope="prototype"/> 10</beans>

2.2.3 编写启动类

1package com.ws.edu.spring; 2 3import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5public class App { 6 @SuppressWarnings("resource") 7 public static void main(String[] args) { 8 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); 9 Person person = context.getBean(Person.class); 10 person.playGame(); 11 } 12}

2.2.4 输出结果

3 自定义方法的替代方案

3.1 用法示例

    使用基于XML配置文件时,你可以使用replaced-method元素来达到用另一个方法来取代已有方法的目的。考虑下面的类,我们将覆盖 computeValue方法。

1public class MyValueCalculator { 2 3 public String computeValue(String input) { 4 // some real code... 5 } 6 7 // some other methods... 8 9}

    实现org.springframework.beans.factory.support.MethodReplacer接口的类提供了新的方法定义。

1/** 2 * meant to be used to override the existing computeValue(String) 3 * implementation in MyValueCalculator 4 */ 5public class ReplacementComputeValue implements MethodReplacer { 6 7 public Object reimplement(Object o, Method m, Object[] args) throws Throwable { 8 // get the input value, work with it, and return a computed result 9 String input = (String) args[0]; 10 ... 11 return ...; 12 } 13}

    下面的bean定义中指定了要配置的原始类和将要复写的方法:

1<bean id="myValueCalculator" class="x.y.z.MyValueCalculator"> 2 <!-- arbitrary method replacement --> 3 <replaced-method name="computeValue" replacer="replacementComputeValue"> 4 <arg-type>String</arg-type> 5 </replaced-method> 6</bean> 7 8<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>

    你可以在<replaced-method/>元素中可以包含多个<arg-type/>元素,这些元素用来标明被复写的方法签名。只有被复写的方法 存在重载的情况和同名的多个方法变体。为了方便,参数的类型字符可以采用全限定类名的简写。例如,下面的字符串都标识参数类型 为java.lang.String

java.lang.String String Str

    因为参数的数目通常足够用来区别每个可能的选择,这个结晶能减少很多键盘输入的工作,它允许你只输入最短的匹配参数类型的字符串。

3.2 代码示例

3.2.1 准备Bean

1package com.ws.edu.spring; 2 3import java.lang.reflect.Method; 4 5import org.springframework.beans.factory.support.MethodReplacer; 6 7public class Game implements MethodReplacer{ 8 9 @Override 10 public Object reimplement(Object obj, Method method, Object[] args) 11 throws Throwable { 12 String gameName = (String)args[0]; 13 System.out.println("playing game:" + gameName); 14 return null; 15 } 16} 17 18 19package com.ws.edu.spring; 20 21public class Person{ 22 public void playGame(String gameName){} 23}

3.2.2 配置xml

1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd" default-lazy-init="true"> 6 <bean id="person" class="com.ws.edu.spring.Person"> 7 <replaced-method name="playGame" replacer="game"> 8 <arg-type>String</arg-type> 9 </replaced-method> 10 </bean> 11 <bean id="game" class="com.ws.edu.spring.Game"/> 12</beans>

3.2.3 编写启动类

1package com.ws.edu.spring; 2 3import org.springframework.context.support.ClassPathXmlApplicationContext; 4 5public class App { 6 @SuppressWarnings("resource") 7 public static void main(String[] args) { 8 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); 9 Person person = context.getBean(Person.class); 10 person.playGame("篮球"); 11 } 12}

3.2.4 输出结果

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Java日期时间API系列31

  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

JAVA记录

singleton作用域:当把一个Bean定义设置为singleton作用域是,SpringIoC容器中只会存在一个共享的Bean实例,并且所有对Bean的请求,只要id与该Bean定义相匹配,则只会返回该Bean的同一实例。值得强调的是singleton作用域是Spring中的缺省作用域。prototype作用域:protot

Spring4 - HelloWorld