问题:
在编写发送邮件工具类MailUtil时,直接使用@Autowired静态注入JavaMailSender,运行时报空指针异常
@Component
public class MailUtil {
@Autowired
private static JavaMailSender mailSender;
}
原因分析:
类变量(用static修饰)是属于类的,在spring容器中都是实例化对象。当我们使用静态变量或静态方法时,不需要new出来一个类的实例化对象,所以使用@Autowired修饰一个静态变量时,该静态变量并没有真正实例化成一个对象,因此该静态变量为null,不能使用 @Autowired来注入静态变量。
解决方案:
代码如下:
@Component
public class MailUtil {
@Autowired
private JavaMailSender JavaMailSender;
private static JavaMailSender mailSender;
@PostConstruct
public void init(){
mailSender = JavaMailSender;
System.out.println("mailSender初始化");
}
}
也可以先加载ApplicationContext (spring上下文环境)
@Component
public class MailUtil {
@Autowired
private ApplicationContext applicationContext;
private static JavaMailSender mailSender;
@PostConstruct
public void init(){
MailUtil.mailSender = applicationContext.getBean(JavaMailSender.class);
System.out.println("mailSender初始化");
}
}
实现原理:
- 类名上使用 @Component 使当前类成为一个bean对象,加入 spring 的管理中。(或者使用 @service)
- 先将需要调用的对象注入进来
- 重新创建一个所需对象的 static 变量
- 写个 @PostConstruct 注解的方法,在这个方法里,初始化在第3步创建的 static 变量,将之前注入的对象赋值给它
- 静态方法中就能够直接进行调用第3步创建的静态变量
关于@PostConstruct
- @PostConstruct注解的方法在项目启动的时候执行这个方法,也可以理解为在spring容器启动的时候执行,可作为一些数据的常规化加载,比如数据字典之类的。
被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,修饰的方法会在构造函数之后,init()方法之前运行。
- 执行顺序:Constructor >> @Autowired >> @PostConstruct
- 需要注意的是,注解会影响到服务器的启动速度。服务器在启动时候会遍历Web 应用的WEB-INF/classes下的所有class文件与WEB-INF/lib下的所有jar文件,以检查哪些类使用了注解。如果应用程序中没有 使用任何注解,可以在Web.xml中设置的metadata-complete属性为true