文档章节

Spring4-容器7-方法注入

王胜_淡如止水
 王胜_淡如止水
发布于 2017/03/26 12:05
字数 1560
阅读 18
收藏 1

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

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

1.1 用法示例

// 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容器的高级特性,可以以一种 干净的方法来处理这种情况。

1.2 代码示例

1.2.1 准备Bean

package com.ws.edu.spring;

public class Game {
}
package com.ws.edu.spring;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class Person implements ApplicationContextAware{
	private ApplicationContext applicationContext;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.applicationContext = applicationContext;
	}
	
	private Game createGame(){
		return applicationContext.getBean(Game.class);
	}
	
	public void playGame(){
		Game game = this.createGame();
		System.out.println("playing game:"+game);
	}
}

1.2.2 配置XML

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

1.2.3 配置启动类

package com.ws.edu.spring;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
		Person person = context.getBean(Person.class);
		person.playGame();
	}
}

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 用法示例

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

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

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

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

    no-arguments不允许有参数。 

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

<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="command" 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="command"/>
</bean>

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

2.2 代码示例

2.2.1 准备Bean

package com.ws.edu.spring;

public class Game {
}
package com.ws.edu.spring;

public class Person{

	public Game createGame(){
		return null;
	}
	
	public void playGame(){
		Game game = this.createGame();
		System.out.println("playing game:"+game);
	}
}

2.2.2 配置Xml

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

2.2.3 编写启动类

package com.ws.edu.spring;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
		Person person = context.getBean(Person.class);
		person.playGame();
	}
}

2.2.4 输出结果

3 自定义方法的替代方案

3.1 用法示例

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

public class MyValueCalculator {

    public String computeValue(String input) {
        // some real code...
    }

    // some other methods...

}

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

/**
 * 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定义中指定了要配置的原始类和将要复写的方法:

<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"/>

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

java.lang.String
String
Str

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

3.2 代码示例

3.2.1 准备Bean

package com.ws.edu.spring;

import java.lang.reflect.Method;

import org.springframework.beans.factory.support.MethodReplacer;

public class Game implements MethodReplacer{

	@Override
	public Object reimplement(Object obj, Method method, Object[] args)
			throws Throwable {
		String gameName = (String)args[0];
		System.out.println("playing game:" + gameName);
		return null;
	}
}
package com.ws.edu.spring;

public class Person{
	public void playGame(String gameName){}
}

3.2.2 配置xml

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

3.2.3 编写启动类

package com.ws.edu.spring;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
		Person person = context.getBean(Person.class);
		person.playGame("篮球");
	}
}

3.2.4 输出结果

© 著作权归作者所有

王胜_淡如止水
粉丝 4
博文 52
码字总数 81235
作品 0
杭州
私信 提问
Spring4新特性——泛型限定式依赖注入

Spring4新特性——泛型限定式依赖注入 Spring4新特性——核心容器的其他改进 Spring4新特性——Web开发的增强 Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC Spring4新特性...

Big_BoBo
2013/12/26
449
0
SSH框架之Spring4专题2:Spring与loC

控制反转(loC,Inversion of Control),是一个概念,是一种思想。指的是将传统上由程序代码直接操纵的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转...

糖醋白糖
2018/06/26
0
0
说说 Spring 的注解配置

1 定义 Bean XML 或注解配置方式,都是表达 Bean 定义的载体,其实质都是为 Spring 容器提供 Bean 定义的信息 。 基于注解的配置方式,从 Spring2.0 开始引入, Spring2.5 完善, Spring4.0 ...

deniro
2018/05/10
0
0
Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

Spring4新特性——泛型限定式依赖注入 Spring4新特性——核心容器的其他改进 Spring4新特性——Web开发的增强 Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC Spring4新特性...

咖啡杯
2014/02/18
284
0
Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

Spring4新特性——泛型限定式依赖注入 Spring4新特性——核心容器的其他改进 Spring4新特性——Web开发的增强 Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC Spring4新特性...

咖啡杯
2014/02/18
5K
0

没有更多内容

加载失败,请刷新页面

加载更多

arduino项目-1. 模拟楼道灯

@toc 1.1 情景说明 说明 漆黑的夜晚,当有人非法进入一所房屋,房屋内的灯在恰当的时间亮起,也许会有效阻止非法活动的继续。 效果展示 1.2 实验器材 器材名称 数量 继电器 1 人体红外感应器...

acktomas
18分钟前
3
0
Nacos 常见问题及解决方法

Nacos 开源至今已有一年,在这一年里,得到了很多用户的支持和反馈。在与社区的交流中,我们发现有一些问题出现的频率比较高,为了能够让用户更快的解决问题,我们总结了这篇常见问题及解决方...

阿里云官方博客
24分钟前
3
0
pinyin4j 满足中文转拼音的需求

引入依赖 // https://mvnrepository.com/artifact/com.belerweb/pinyin4j //汉字转拼音compile group: 'com.belerweb', name: 'pinyin4j', version: '2.5.1' 写入中文转拼英的工具......

edison_kwok
30分钟前
3
0
IPSE接入Substrate/Polkadot插槽实现互操作性的运行原理

Substrate框架将区块链的众多功能都模块化,对于开发者来说,只是一个选择的问题,同时还保持了众多的可以定制的功能和模块,比如底层通信模块,比如账户体系,比如共识机制等都是可以自己定...

IPSE
36分钟前
155
0
linux配置安装phpMyAdmin的步骤记录

1、首先在phpMyAdmin官方网站 http://www.phpmyadmin.net/downloads下载源码包,或者通过脚本之家进行下载://www.jb51.net/codes/405261.html ,下载后上传到服务器解压即可,或者通过Linux...

蜗牛女孩
37分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部