singleton实例依赖于prototype实例,ProtoType含义是无效的,必须钩入向Spring容器请求,也就是调用getBean方法。换句话说,我们必须改变依赖关系的注入。
例如A的scope是 Singleton ,B的scope是Prototype,当A依赖B时,B实例会在第一次初始化请求创建,之后的对A的调用间接依赖的B仍旧是同一实例,这并非B所声明的scope=Prototype含义。
// 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;
}
}
上述createCommand方法里调用了getBean方法改变了依赖注入方式。但是还有一点“瑕疵”:依赖了ApplicationContext。这种任务Spring也提供了,因为诞生初衷就是为了减少代码的耦合程度,所以有了后来的控制反转。Look up method解决了这个问题。只要对每个要使用getBean代码的方法配置一个Bean(不支持一个方法对应多个Bean),注意替换的方法是无参的<!-- 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>
现在代码不再依赖于Springpackage 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();
}
很少使用但很强大的同宗replace method
lookup method只是替换了getBean这样的简单代码,而replace method它将深入到指定bean之后的方法调用中,即MethodReplacer的方法reimplement,这里可以做更多的事,显然它支持并且一定比较可能重载的方法。
/** 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"/>
实现
之前提到过AbstractBeanFactory,其子类AbstractAutowireCapableBeanFactory实现了instantiateBean方法
再进入SimpleInstantiationStrategy,可以看到如果有方法覆盖将调用instantiateWithMethodInjection,否则使用反射机制实例化public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (beanDefinition.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse;
synchronized (beanDefinition.constructorArgumentLock) {
constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class clazz = beanDefinition.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
public Constructor run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Exception ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(beanDefinition, beanName, owner);
}
}
SimpleInstantiationStrategy子类CglibSubclassingInstantiationStrategy实现了instantiateWithMethodInjection方法,显然method注入的两种方式都是使用Cglib实现的。
setSuperclass:设置要代理的父类
setCallbackFilter:设置过滤器,有一个accept方法返回拦截器的索引值:
lookup method 该方法使用lookup method
replace method 改方法使用replace method
not found 不对方法拦截
setCallbacks:设置拦截器public Object instantiate(Constructor ctor, Object[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.beanDefinition.getBeanClass());
enhancer.setCallbackFilter(new CallbackFilterImpl());
enhancer.setCallbacks(new Callback[] {
NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(),
new ReplaceOverrideMethodInterceptor()
});
return (ctor == null) ?
enhancer.create() :
enhancer.create(ctor.getParameterTypes(), args);
}
lookup method拦截private class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
// Cast is safe, as CallbackFilter filters are used selectively.
LookupOverride lo = (LookupOverride) beanDefinition.getMethodOverrides().getOverride(method);
return owner.getBean(lo.getBeanName());
}
}
replace method拦截private class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
ReplaceOverride ro = (ReplaceOverride) beanDefinition.getMethodOverrides().getOverride(method);
// TODO could cache if a singleton for minor performance optimization
MethodReplacer mr = (MethodReplacer) owner.getBean(ro.getMethodReplacerBeanName());
return mr.reimplement(obj, method, args);
}
}
- 大小: 6.3 KB
- 大小: 54.4 KB
分享到:
相关推荐
而"InjectionExample.zip"可能包含示例代码或应用程序,让用户能够直观地了解和学习这种方法替换器的工作原理。 在实际应用中,理解并掌握CLR注入和运行时方法替换的概念和技术,可以帮助开发者实现高级的调试技巧...
这种技术可以用于动态添加或修改方法的行为,甚至可以实现动态插件系统。IL注入通常包括以下步骤: 1. 反编译:使用反编译工具(如IL Dasm)将已编译的.NET程序集转换为IL代码。 2. 修改IL:找到并修改IL代码以实现...
其次,Java反射机制是Java的一大特色,它允许我们在运行时检查类、接口、字段和方法的信息,甚至动态调用方法和改变字段值。反射在许多场景下都非常有用,比如在框架开发、元数据处理、动态代理等。通过Class类、...
- **Spring的依赖**:可以使用`lookup-method`和`replaced-method`对方法进行替换或动态查找。 - **Spring的p命名空间**:提供了一种更简洁的方式来配置bean属性。例如: ```xml 张三" p:age="22"/> ``` - **...
Spring框架是Java开发中最常用的轻量级框架之一,它的核心特性是依赖注入(Dependency Injection,简称DI),也常被称为控制反转(Inversion of Control,简称IoC)。控制反转是一种设计模式,它改变了传统应用程序...
理解面向对象编程的基本原则,如单一职责原则、开闭原则、里氏替换原则、依赖倒置原则和接口隔离原则。 2. **异常处理**:理解异常的分类,如检查型异常和运行时异常,掌握try-catch-finally语句块的用法,以及如何...
- **init-method/destroy-method**:定义Bean的初始化和销毁方法。 #### 第六课:Annotation方式Spring 1. **开始使用annotation配置Spring**:从Spring 2.5开始,支持使用注解来进行Bean的配置。 2. **@...
在Python开发过程中,依赖注入(Dependency Injection,简称DI)是一种常用的软件设计模式,它有助于实现代码的松耦合和可测试性。`siringa`是一个轻量级的库,专注于使用Python的注释语法来实现依赖注入,使得代码...
- **初始化**:调用bean的初始化方法,如`@PostConstruct`或`init-method`属性指定的方法。 - **运行时**:bean处于可用状态。 - **销毁**:调用bean的销毁方法,如`@PreDestroy`或`destroy-method`属性指定的方法。...
SOLID原则包括单一职责原则(Single Responsibility Principle)、开放封闭原则(Open/Closed Principle)、里氏替换原则(Liskov Substitution Principle)、接口隔离原则(Interface Segregation Principle)和...
3. 方法注入(Method Injection):依赖对象是通过一个公共方法传入。 以上三种方式在实际应用中可以单独使用,也可以组合使用。其中,构造函数注入是最常见的实践方式,因为它能保证在对象创建时依赖关系就已经被...
- **RMI**(Remote Method Invocation): - 面向对象的远程过程调用技术。 - 要求客户端和服务端都必须是Java环境。 - **WebService**: - 基于标准协议(如XML、SOAP、HTTP等)的分布式服务技术。 - 支持跨...
- **DI (Dependency Injection)**:依赖注入,是实现 IOC 的一种手段,它将一个对象所依赖的其他对象注入给它,而不是由该对象自己创建或查找依赖对象。 **好处**: 1. **降低耦合度**:通过依赖注入,各个组件之间...