2

单例bean注入多例bean

MyPrototype、MyController

@Component
@Scope("prototype")
public class MyPrototype {
}
@Controller
public class MyController {
    @Autowired
    MyPrototype myPrototype;
    public MyPrototype getMyPrototype() {
        return myPrototype;
    }
}

MyConfig

@Configuration
@ComponentScan(value="com.learn.annotation2")
public class MyConfig {

}

测试代码

@Test
public void test(){
    ApplicationContext app =  new AnnotationConfigApplicationContext(MyConfig.class);
    MyController myController=app.getBean("myController",MyController.class);
    System.out.println(myController.getMyPrototype());
    System.out.println(myController.getMyPrototype());
}

运行结果如下:
image.png
可以看出,当单例myController中注入了多例的myPrototype,myPrototype对于myController还是一个实例,如果我们想每次获取的myPrototype是不一样的,要怎么办呢?

ApplicationContextAware

重写MyController,继承ApplicationContextAware接口设置ApplicationContext,并重写getMyPrototype方法通过applicationContext获取bean。

@Controller
public class MyController implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    @Autowired
    MyPrototype myPrototype;

    public MyPrototype getMyPrototype() {
        return applicationContext.getBean("myPrototype",MyPrototype.class);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

测试代码不变
运行结果如下:
image.png
可以看出这两个地址不一样。但是这样的处理是不优雅的,业务代码和spring框架耦合度太高。

@Lookup

如果是XML配置的话,用lookup-method标签,比如:

<bean id="commandManager" class="com.learn.di.CommandManager">
    <lookup-method name="createCommand" bean="myCommand"/>
</bean>

MyController改写如下:

@Controller
public abstract class MyController{
    @Autowired
    MyPrototype myPrototype;

    public MyPrototype getMyPrototype() {
        return createMyPrototype();
    }

    @Lookup()
    protected abstract MyPrototype createMyPrototype() ;
}

测试代码等其他不变。
运行结果如下:
image.png
通过@Lookup注解,可以看出,两次的地址是不一样的。

方法替换

di.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" xmlns:c="http://www.springframework.org/schema/c"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myValueCalculator" class="com.learn.di.MyValueCalculator">
        <replaced-method name="computeValue" replacer="replacementComputeValue">
            <arg-type>String</arg-type>
        </replaced-method>
    </bean>

    <bean id="replacementComputeValue" class="com.learn.di.ReplacementComputeValue"/>
</beans>

MyValueCalculator和ReplacementComputeValue

public class MyValueCalculator {
    public String computeValue(String input) {
        System.out.println(input);
        return "old method";
    }
}
public class ReplacementComputeValue implements MethodReplacer {

    @Override
    public Object reimplement(Object o, Method method, Object[] objects) throws Throwable {
        return "new method";
    }
}

测试代码

@Test
public void test11() {
    ApplicationContext app = new ClassPathXmlApplicationContext("di10.xml");
    MyValueCalculator myValueCalculator = app.getBean("myValueCalculator", MyValueCalculator.class);
    System.out.println(myValueCalculator.computeValue("input"));
}

运行结果如下:
image.png
在配置文件中,设置了myValueCalculator类中的computeValue方法,由replacementComputeValue的方法替换,最终调用的是replacementComputeValue的reimplement方法,输出new method。


大军
847 声望183 粉丝

学而不思则罔,思而不学则殆