通常情况下我们在spring中定义的常用bean都是单例模式(singleton)的例如@Service、@Controller定义的bean,任何一个类都只有一个对象,只进行一次初始化这些类的属性永远是最后一次调用它时的值。但是针对不同的业务场景我们可能会定义一些bean,这些bean的属性在不同场景下它的属性值是不同的,因此这时候我们就不能使用单例模式了而使用原型模式(prototype),这种模式相当于new一个对象。参见spring官方文档。
1.4.6. Method injection
In most application scenarios, most beans in the container are singletons. When a singleton bean needs to collaborate with another singleton bean, or a non-singleton bean needs to collaborate with another non-singleton bean, you typically handle the dependency by defining one bean as a property of the other. A problem arises when the bean lifecycles are different. Suppose singleton bean A needs to use non-singleton (prototype) bean B, perhaps on each method invocation on A. The container only creates the singleton bean A once, and thus only gets one opportunity to set the properties. The container cannot provide bean A with a new instance of bean B every time one is needed.
最后两句:假定有单例bean A和原型bean B,当A初始化的时候只有一次机会初始化B,但是A中可能在不同方法中对B进行了调用,这时候可能B中的部分属性发生了变化,而在A中的不同方法可能希望B中的属性是刚初始化时的值,但是容器并不能提供新的B类的实体,因此才有了下面的解决办法
A solution is to forego some inversion of control. You can make bean A aware of the container by implementing the ApplicationContextAware interface, and by making a getBean(“B”) call to the container ask for (a typically new) bean B instance every time bean A needs it. The following is an example of this approach:
利用ApplicationContextAware接口中的getBean方法向容器请求一个新的bean
具体参考以下代码
package com.spring.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @author chengjian
* @date 2018/5/16
**/
@Component
public class SpringBeanFactory implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
}
public <T> T getBean(Class<T> clazz){
try{
return applicationContext.getBean(clazz);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
我们创建了一个SpringBeanFactory,这个类实现了ApplicationContextAware方法,我们在类中新定义了一个基于泛型的getBean方法,通过这样的方式我们就能通过方法的方式从spring容器中获取到我们想要的bean。参考下面的代码
package com.spring.javatest.io;
import com.github.javafaker.Faker;
import com.spring.config.SpringConfig;
import com.spring.javatest.entity.UserEntity;
import com.spring.util.CommonUtil;
import com.spring.util.SpringBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.Locale;
/**
* @author chengjian
* @date 2018/5/15
**/
@Component
public class OutPutStreamTest {
@Autowired
private SpringBeanFactory springBeanFactory;
public void fileOutPutSerializable() {
try {
Faker faker=new Faker(new Locale("zh-CN"));
UserEntity user=new UserEntity();
user.setUserid(CommonUtil.getUuid());
user.setUserpwd("123456");
user.setUsername("a001");
user.setRealname(faker.name().fullName());
String fileName = springBeanFactory.getBean(SpringConfig.class).getLocation() + "output";
FileOutputStream f = new FileOutputStream(fileName);
ObjectOutput s = new ObjectOutputStream(f);
s.writeObject(user);
s.flush();
s.close();
f.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
我们并没有通过@Autowired注解注入SpringConfig,而是通过方法注入的方式注入的bean