原创

Spring静态注入bean的四种方式

欢迎转载:攻城狮不是猫 

春天静态注入的四种方式:

(说明:MongoFileOperationUtil是自己封装的一个的MongoDB的文件读写工具类,里面需要依赖AdvancedDatastore对象实例,dsForRW用来获取的MongoDB的数据源)

在springframework里,我们不能@Autowired一个静态变量,使之成为一个spring bean,例如下面这种方式:

  1. @Autowired
  2. private static AdvancedDatastore dsForRW;

可以试一下,dsForRW 在这种状态下不能够依赖注入,会抛出运行时异常java.lang.NullPointerException,为什么呢?静态变量/类变量不是对象的属性,而是一个类的属性,spring则。基于的英文层面对象上的依赖注入
但是自己比较喜欢封装工具类,并通过@Component注解成功能组件,但是功能组件中的方法一般都是静态方法,静态方法只能调用静态成员变量,于是就有了下面的问题。有的封封装时候功能组件会需要底层的服务注入,怎么办呢?

去网上搜了下解决办法,简单总结一下几种实现方式;

1.XML方式实现;

  1. <bean id="mongoFileOperationUtil" class="com.*.*.MongoFileOperationUtil" init-method="init">
  2. <property name="dsForRW" ref="dsForRW"/>
  3. </bean>


  1. public class MongoFileOperationUtil {
  2. private static AdvancedDatastore dsForRW;
  3. private static MongoFileOperationUtil mongoFileOperationUtil;
  4. public void init() {
  5. mongoFileOperationUtil = this;
  6. mongoFileOperationUtil.dsForRW = this.dsForRW;
  7. }
  8. }

这种方式适合基于XML配置的WEB项目;


2. @ PostConstruct方式实现;

  1. import org.mongodb.morphia.AdvancedDatastore;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. @Component
  4. public class MongoFileOperationUtil {
  5. @Autowired
  6. private static AdvancedDatastore dsForRW;
  7. private static MongoFileOperationUtil mongoFileOperationUtil;
  8. @PostConstruct
  9. public void init() {
  10. mongoFileOperationUtil = this;
  11. mongoFileOperationUtil.dsForRW = this.dsForRW;
  12. }
  13. }

@PostConstruct注解的方法在加载类的构造函数之后执行,也就是在加载了构造函数之后,执行init方法;(@ PreDestroy注解定义容器销毁之前的所做的操作)

这种方式和在xml中配置 init-method和 destory-method方法差不多,定义spring 容器在初始化bean 和容器销毁之前的所做的操作;

3.set方法上添加@Autowired注解,类定义上添加@Component注解;

  1. import org.mongodb.morphia.AdvancedDatastore;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.stereotype.Component;
  4. @Component
  5. public class MongoFileOperationUtil {
  6. private static AdvancedDatastore dsForRW;
  7. @Autowired
  8. public void setDatastore(AdvancedDatastore dsForRW) {
  9. MongoFileOperationUtil.dsForRW = dsForRW;
  10. }
  11. }

首先Spring要能扫描到AdvancedDatastore的bean,然后通过setter方法注入;

然后注意:成员变量上不需要再添加@Autowired注解;  

4. BeanFactoryAware、ApplicationContextAware

Spring提供了两个接口:BeanFactoryAware和ApplicationContextAware,这两个接口都继承自Aware接口。如下是这两个接口的声明:

public interface BeanFactoryAware extends Aware {
    void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

       在Spring官方文档中描述,在初始化Spring bean时,如果检测到某个bean实现了这两个接口中的一个,那么就会自动调用该bean所实现的接口方法。这里可以看到,这两个方法都是将IoC容器管理bean的工厂对象传递给当前bean,也就是说如果我们在当前bean中将工厂对象保存到某个静态属性中,那么我们就能够通过工厂对象获取到我们需要的bean。如下是使用ApplicationContextAware实现的一个SpringBeanUtil:

public class SpringBeanUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    public void setApplicationContext(ApplicationContext applicationContext) 
      throws BeansException {
        SpringBeanUtil.applicationContext = applicationContext;
    }

    public static <T> T getBean(Class<T> clazz) {
        return (T) applicationContext.getBean(clazz);
    }

    public static Object getBean(String name) throws BeansException {

        return applicationContext.getBean(name);
    }
}

       这里还需要在配置文件中指定创建当前类的一个实例:

<bean id="springBeanFactory"/>

       可以看到,我们再SpringBeanUtil中声明了一个ApplicationContext的类型的静态属性,并且在setApplicationContext()方法中将获取到的ApplicationContext的赋值给了该静态属性,这样我们就可以在另外两个声明的静态方法中通过ApplicationContext中获取的IoC容器所管理的豆了如下是一个测试示例:

public class ClassRoom {
  public void describeStudent() {
    Student student = SpringBeanUtil.getBean(Student.class);
    System.out.println(student);
  }

  public static void describeClassRoomCapacity() {
    Student student = SpringBeanUtil.getBean(Student.class);
    System.out.println("Is it not empty? " + (null != student));
  }
}
public class Student {
  @Override
  public String toString() {
    return "I am a student.";
  }
}
<bean id="springBeanFactory"/>
<bean id="student"/>

如下是驱动类:

public class BeanApp {
  public static void main(String[] args) {
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("com/resources/application.xml");
    ClassRoom.describeClassRoomCapacity();
    ClassRoom classRoom = new ClassRoom();
    classRoom.describeStudent();
  }
}

       在驱动类中,我们首先使用的ClassPathXmlApplicationContext的加载配置文件中的豆。可以看到,我们创建了一个SpringBeanUtil和一个学生的豆。我们首先在静态方法中获取了学生实例,并将其打印出来了,我们也在新出来的课堂实例中通过SpringBeanUtil获取了学生实例,并且对其进行了输出如下是输出结果:

Is it not empty? true
I am a student.

        可以看到,无论是在静态方法中,还是在手动新的实例中,我们都成功获取了的的IoC容器所管理的豆。如果我们想在静态属性中获取SpringBean,其实也非常简单,直接对属性赋值即可,如下所示:

private static Student student = SpringBeanUtil.getBean(Student.class);

参考:HTTPS://blog.csdn.net/chen1403876161/article/details/53644024

https://www.cnblogs.com/zhangxufeng/p/9162184.html

正文到此结束
Loading...