1. 程式人生 > >Spring框架下Bean的方法注入(Method injection)

Spring框架下Bean的方法注入(Method injection)

通常情況下我們在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