springboot对已有自动装配组件进行自定义
背景
项目使用了spring的javamailsender来发邮件,使用了springboot的自动装配的javamailsender对象
MailSenderPropertiesConfiguration,在application.yml里指定了spring.mail.xxx属性,包括用户名,密码等等配置,使用时,直接引用@Autowired private JavaMailSender mailSender;使用即可。
MailSenderPropertiesConfiguration中,暴露bean的方法用@Bean修饰,未指定bean名称,默认的bean名称是用方法名的首字母小写的方法名,作为bean名称,即mailSender。
安全要求对密码进行加密,不能明文存储在yml文件里。
加密动作,假设有读写的接口可以用
那这个密码怎么在javamailsender里使用呢?
方法1:自行声明,覆盖springboot自动装配的bean
参考:
@ConfigurationProperties 与 @EnableConfigurationProperties_51CTO博客_@EnableConfigurationProperties
@ConfigurationProperties使用技巧 - 掘金
通过自己提供spring自动装配的bean,覆盖掉spring的。
仿照spring自动装配声明的方式,通过@Bean来暴露一个JavaMailSender。代 码如下:
@Configuration
@EnableConfigurationProperties(MailProperties.class)
public class JavaMailSenderConfig {
@Autowired
private MailProperties properties;
@Bean
@ConditionalOnMissingBean(JavaMailSender.class)
public JavaMailSenderImpl mailSender() {
JavaMailSenderImpl sender = new JavaMailSenderImpl();
applyProperties(sender);
return sender;
}
private void applyProperties(JavaMailSenderImpl sender) {
sender.setHost(this.properties.getHost());
if (this.properties.getPort() != null) {
sender.setPort(this.properties.getPort());
}
# 在这里,使用了从kconf读取的用户名和密码
sender.setUsername(resolveUserName());
sender.setPassword(resolvePassword());
sender.setProtocol(this.properties.getProtocol());
if (this.properties.getDefaultEncoding() != null) {
sender.setDefaultEncoding(this.properties.getDefaultEncoding().name());
}
if (!this.properties.getProperties().isEmpty()) {
sender.setJavaMailProperties(asProperties(this.properties.getProperties()));
}
}
private Properties asProperties(Map<String, String> source) {
Properties properties = new Properties();
properties.putAll(source);
return properties;
}
private String resolveUserName() {
//通过接口获取用户名
return this.properties.getUsername();
}
private String resolvePassword() {
//通过接口获取密码
return this.properties.getPassword();
}
}
方法2:使用BeanPostprocessor,覆盖属性。
参考:
Spring之BeanFactoryPostProcessor和BeanPostProcessor - 掘金
这种方法的思路,是在spring中,使用BeanPostProcessor,在bean实例化完成之后,执行操作,用kconf里的配置,覆盖其原本的用户名和密码。
@Component
public class JavaMailSenderBeanPostProcesser implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof JavaMailSenderImpl){
JavaMailSenderImpl javaMailSenderImpl = (JavaMailSenderImpl) bean;
# 在这里重新设置用户名和密码
javaMailSenderImpl.setUsername(获取到的用户名);
javaMailSenderImpl.setPassword(获取到的密码);
return javaMailSenderImpl;
}else{
return bean;
}
}
}