Spring静态注入bean的四种方式 痛定思痛。 2022-05-15 01:58 872阅读 0赞 ## **欢迎转载:[攻城狮不是猫][Link 1] ** ## Spring静态注入的四种方式: (说明:MongoFileOperationUtil是自己封装的一个Mongodb文件读写工具类,里面需要依赖AdvancedDatastore对象实例,dsForRW用来获取Mongodb数据源) 在springframework里,我们不能@Autowired一个静态变量,使之成为一个spring bean,例如下面这种方式: 1. `@Autowired` 2. `private static AdvancedDatastore dsForRW;` 可以试一下,dsForRW在这种状态下不能够被依赖注入,会抛出运行时异常java.lang.NullPointerException,为什么呢?静态变量/类变量不是对象的属性,而是一个类的属性,spring则是基于对象层面上的依赖注入。 但是自己比较喜欢封装工具类,并通过@Component注解成功能组件,但是功能组件中的方法一般都是静态方法,静态方法只能调用静态成员变量,于是就有了下面的问题。封有的时候封装功能组件会需要底层的service注入,怎么办呢? 去网上搜了下解决办法,简单总结一下几种实现方式; 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. 3. `private static AdvancedDatastore dsForRW;` 4. 5. `private static MongoFileOperationUtil mongoFileOperationUtil;` 6. 7. `public void init() {` 8. `mongoFileOperationUtil = this;` 9. `mongoFileOperationUtil.dsForRW = this.dsForRW;` 10. `}` 11. 12. `}` 这种方式适合基于XML配置的WEB项目; 2.@PostConstruct方式实现; 1. `import org.mongodb.morphia.AdvancedDatastore;` 2. `import org.springframework.beans.factory.annotation.Autowired;` 3. 4. 5. `@Component` 6. `public class MongoFileOperationUtil {` 7. `@Autowired` 8. `private static AdvancedDatastore dsForRW;` 9. 10. `private static MongoFileOperationUtil mongoFileOperationUtil;` 11. 12. `@PostConstruct` 13. `public void init() {` 14. `mongoFileOperationUtil = this;` 15. `mongoFileOperationUtil.dsForRW = this.dsForRW;` 16. `}` 17. 18. `}` @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. 5. 6. `@Component` 7. `public class MongoFileOperationUtil {` 8. 9. `private static AdvancedDatastore dsForRW;` 10. 11. `@Autowired` 12. `public void setDatastore(AdvancedDatastore dsForRW) {` 13. `MongoFileOperationUtil.dsForRW = dsForRW;` 14. `}` 15. `}` 首先Spring要能扫描到AdvancedDatastore的bean,然后通过setter方法注入; 然后注意:成员变量上不需要再添加@Autowired注解; **4. BeanFactoryAware,ApplicationContextAware** 春天提供了两个接口:实现了BeanFactoryAware和了了ApplicationContextAware,这两个接口都继承自感知接口如下是这两个接口的声明: 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实现了这两个接口中的一个,那么就会自动调用该豆所实现的接口方法。这里可以看到,这两个方法都是将的的IoC容器管理的豆腐的工厂对象传递给当前豆,也就是说如果我们在当前豆中将工厂对象保存到某个静态属性中,那么我们就能够通过工厂对象获取到我们需要的豆如下是使用了了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 [Link 1]: http://www.jsdblog.com/article/275
还没有评论,来说两句吧...