问题

最近项目组正在重新规划项目的业务缓存,其中涉及到一些代码重构。在这个过程中,发现工具类中的一些静态方法需要依赖其他对象实例(这个实例已经在xml中配置为Spring bean,非Static可以用@Autowired加载来正常使用),我们知道类加载后,静态成员都在内存的共享区域,静态方法中的变量必须使用静态成员变量,这就导致了下面的代码:

@组件
公共测试类{

    @Autowired
    私有静态 AutowiredTypeComponent 组件;

    //调用静态组件的方法
    公共静态void testMethod() {
        组件.callTestMethod();
    }

}

编译正常,但是运行时出现java.lang.NullPointerException: null异常。显然,调用testMethod()方法时,组件变量还没有初始化,就报NPE。

原因

所以,在Springframework中,我们不能@Autowired一个静态变量来使其成为一个Spring bean。为什么?其实很简单,因为当类加载器加载静态变量时,Spring上下文还没有加载。所以类加载器不会正确地将静态类注入到bean中并且会失败。

解决方案

将@Autowired注释到类的构造函数中。很容易理解,Spring会扫描AutowiredTypeComponent的bean,然后将其赋值给静态变量组件。例子如下:

@组件
公共测试类{

    私有静态 AutowiredTypeComponent 组件;@Autowired
    公共TestClass(AutowiredTypeComponent组件){
        TestClass.component = 组件;
    }

    //调用静态组件的方法
    公共静态void testMethod() {
        组件.callTestMethod();
    }

}

在静态组件中添加一个setter方法,并在该方法中添加@Autowired。 Spring可以扫描AutowiredTypeComponent bean并通过setter方法注入它。例子如下:

@组件
公共测试类{

    私有静态 AutowiredTypeComponent 组件;

    @Autowired
    public void setComponent(AutowiredTypeComponent 组件){
        TestClass.component = 组件;
    }

    //调用静态组件的方法
    公共静态void testMethod() {
        组件.callTestMethod();
    }

}

定义一个静态组件,定义一个非静态组件并添加@Autowired注解,然后定义一个方法来初始化组件并添加@PostConstruct注解。该注解由JavaEE引入并作用于servlet生命周期。你只需要知道用它注释的方法会在构造函数之后被调用。例子如下:

@组件公共测试类{

   私有静态 AutowiredTypeComponent 组件;

   @Autowired
   私有 AutowiredTypeComponent autowiredComponent;

   @PostConstruct
   私有void beforeInit() {
      组件 = this.autowiredComponent;
   }

   //调用静态组件的方法
   公共静态void testMethod() {
      组件.callTestMethod();
   }

}

直接使用Spring框架工具类获取bean并定义为局部变量。但也有缺点:如果类中有多个静态方法多次使用该组件,则每次都必须通过这种方式获取。我个人不推荐这种方法。例子如下:

公共类测试类{

    //调用静态组件的方法
   公共静态void testMethod() {
      AutowiredTypeComponent 组件 = SpringApplicationContextUtil.getBean("组件");
      组件.callTestMethod();
   }

}

总结

  1. 在上面的代码示例中,我为每个类添加了 @Component 注解。事实上,可以根据需要进行更改。比如这个类处理业务逻辑,可以用@Service来代替;该类处理转发或者重定向的请求,可以改为@Controller(Spring-mvc的注解);这个类是专门用来操作Dao的,所以是@Repository。 Spring的注解对你做了一件非常有意义的事情:它们对应用程序进行分层,使得请求处理、业务逻辑处理和数据库操作处理可以分离,解耦代码,让项目变得更简单。开发和维护。

  2. Spring容器bean加载机制使用Java反射。这里我就不详细说了。我会专门写一篇文章来总结一下Java反射在Spring的IoC和AoP中的应用。