SpringBoot中Utils中无法注入Bean
问题:
使用springboot的JavaMailSender 发送邮件时一直注入不了。
@Autowired
private JavaMailSender javaMailSender;
原始代码:
@Autowired
private JavaMailSender javaMailSender;
public static void sendMail(String receiveEmail, String emailSubject, String emailText){
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("website@aamazedata.com");
message.setTo(receiveEmail);
message.setText(emailText);
message.setSubject(emailSubject);
javaMailSender.send(message);
}
上面的这样测试时一直在报空指针异常,提示无法注入JavaMailSender。
有两种解决方法:
一、 使用applicationContext的getBean方法即可实现。
public static void sendMail(String receiveEmail, String emailSubject, String emailText){
JavaMailSender javaMailSender = ApplicationContextUtil.get(JavaMailSender.class);
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("website@aamazedata.com");
message.setTo(receiveEmail);
message.setText(emailText);
message.setSubject(emailSubject);
javaMailSender.send(message);
}
ApplicationContextUtill:
@Configuration
public class ApplicationContextUtil implements ApplicationContextAware {
// 定义静态的ApplicationContext成员对象
private static ApplicationContext applicationContext;
// 重写setApplicationContext方法,把参数中的ApplicationContext对象赋值给类静态成员
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextUtil.applicationContext = applicationContext;
}
// 定义get方法,参数为Class,调用上下文的getBean方法获取容器中的指定对象
public static <T> T get(Class<T> clazz){
return applicationContext.getBean(clazz);
}
// 同上,参数为对象名
public static Object get(String name) {
return applicationContext.getBean(name);
}
}
个人感觉上面这个类其实的核心还是ApplicationContext,直接调用ApplicationContext。getBean()应该就可以。
上面是使用自己定义的ApplicationContextUtil来获取Spring配置文件中的实例方法。
当然还有许多现成的工具类: SpringUtils.getBean() 、 SpringContextUtil.getBean()都可以。
二、 使用@PostConstruct注解,专门可以解决在静态方法中调用依赖注入的Bean中的方法。
@PostConstruct注解好多人以为是Spring提供的。其实是java自己的注解。
java中该注解的说明:@PostConstruct该注解被用来修饰一个非静态的void()方法。该@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且服务器只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。
通常我们会是在Spring框架中使用@PostConstruct注解。该注解在整个Bean初始化中的执行顺序是: Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)。
解决方法
1、首先在MailUtis上添加@Component声明其为bean组件
2、使用Autowired注入要注入的那个类(JavaMailSender)
3、在MailUtils中声明一个静态的私有变量private static MailUtils mailUtils;
4、添加共有的init方法,并使用@PostConstruct声明在项目启动的时候进行执行该方法,也可以理解为在Spring容器初始化的时候执行该方法。
代码变为:
@Component
public class MailUtils {
@Autowired
private JavaMailSender javaMailSender;
private static MailUtils mailUtils;
@PostConstruct
public void init(){
mailUtils = this;
mailUtils.javaMailSender = this.javaMailSender;
}
public static void sendMail(String receiveEmail, String emailSubject, String emailText){
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("website@aamazedata.com");
message.setTo(receiveEmail);
message.setText(emailText);
message.setSubject(emailSubject);
mailUtils.javaMailSender.send(message);
}
}
上面的办法亲测可用。
上面的办法也可以解决下面的问题:
当我们自己创建了配置类:
@Configuration
public class MailAccountConfig implements ApplicationContextAware {
@Value("${email.host}")
private String host;
@Value("${email.port}")
private Integer port;
@Value("${email.from}")
private String from;
@Value("${email.user}")
private String user;
@Value("${email.pass}")
private String pass;
@Value("${email.ssLEnable}")
private Boolean ssLEnable;
@Bean
public MailAccount mailAccount(){
MailAccount mailAccount = new MailAccount();
mailAccount.setHost(host);
mailAccount.setPort(port);
mailAccount.setAuth(true);
mailAccount.setFrom(from);
mailAccount.setUser(user);
mailAccount.setPass(pass);
mailAccount.setSslEnable(ssLEnable);
return mailAccount;
}
当想自己使用这个Bean时,你会发现在Utils中还是不能注入,这时还是借鉴上面的PostConstruct注解解决。
SpringBoot的Utils中还不能读取Application.yml中配置的属性
遇到这种情况时,首先考虑Spring接口类Environment:
- Spring 为运行环境提供了的高度的抽象接口,项目运行中的所有配置都是基于此接口,用来表示整个应用运行时的环境。
- 该接口继承自PropertyResolver, 而PropertyResolver规范了解析底层任意property资源,也就意味着application.yml是由ProprttyResolver管理。
- PropertyResolver提供了方法getProperty(String key) ,该方法通过传入properties文件中定义的key,返回与给定键关联的属性值。
因此使用下面的代码即可实现在Utils中自由读取配置文件中自定义的所有属性。
public static String getProperty(){
Environment environment = ApplicationContextUtil.get(Environment.class);
String host = environment.getProperty("spring.mail.host");
logger.info(host);
String port = environment.getProperty("spring.mail.port");
logger.info(port);
String username = environment.getProperty("spring.mail.username");
logger.info(username);
String password = environment.getProperty("spring.mail.password");
logger.info(password);
String protocol = environment.getProperty("spring.mail.protocol");
logger.info(protocol);
return null;
}