最近项目组正在重新规划项目的业务缓存,其中涉及到一些代码重构。在这个过程中,发现工具类中的一些静态方法需要依赖其他对象实例(这个实例已经在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();
}
}
在上面的代码示例中,我为每个类添加了 @Component 注解。事实上,可以根据需要进行更改。比如这个类处理业务逻辑,可以用@Service来代替;该类处理转发或者重定向的请求,可以改为@Controller(Spring-mvc的注解);这个类是专门用来操作Dao的,所以是@Repository。 Spring的注解对你做了一件非常有意义的事情:它们对应用程序进行分层,使得请求处理、业务逻辑处理和数据库操作处理可以分离,解耦代码,让项目变得更简单。开发和维护。
Spring容器bean加载机制使用Java反射。这里我就不详细说了。我会专门写一篇文章来总结一下Java反射在Spring的IoC和AoP中的应用。