【问题标题】:@Value not inject data from application.properties@Value 不从 application.properties 注入数据
【发布时间】:2018-08-16 15:55:28
【问题描述】:

我会给你看一个小代码,然后我会问一个问题。

SendEmail.java

package com.goode;

import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

@Component
@NoArgsConstructor
@Data
@AllArgsConstructor
public class SendEmail {

  @Value("${email.username}")
  private String username;

  @Value("${email.password}")
  private String password;

  @Value("${email.fullAddress}")
  private String fullAddress;

  @Value("${email.host}")
  private String host;

  @Value("${email.port}")
  private String port;

  public boolean send(String toEmail, String subject, String message){
    Properties props = new Properties();
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.starttls.enable", "true");
    props.put("mail.smtp.host", host);
    props.put("mail.smtp.port", port);

    Session session = Session.getInstance(props,
        new javax.mail.Authenticator() {
          protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(username, password);
          }
        });

    try {
      Message createMessage = new MimeMessage(session);
      createMessage.setFrom(new InternetAddress(fullAddress));
      createMessage.setRecipients(Message.RecipientType.TO,
          InternetAddress.parse(toEmail));
      createMessage.setSubject(subject);
      createMessage.setText(message);
      Transport.send(createMessage);

      return true;

    } catch (MessagingException e) {
      throw new RuntimeException(e);
    }
  }

  @Bean
  public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer()
  {
    PropertySourcesPlaceholderConfigurer o = new PropertySourcesPlaceholderConfigurer();
    o.setLocation(new ClassPathResource("application.properties"));
    return o;
  }
}

RootConfig.java

package com.goode.config;

import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableJpaRepositories( basePackages = {"com.goode.repository"})
@PropertySource(value = { "classpath:application.properties" })
@EnableTransactionManagement
@Import({ SecurityConfig.class })
@ComponentScan(basePackages = {"com.goode.service", "com.goode.repository", "com.goode.controller", "com.goode.business", "com.goode"})
public class RootConfig {

  @Autowired
  private Environment environment;

  @Autowired
  private DataSource dataSource;

  @Bean
  public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
    dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
    dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
    dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));

    return dataSource;
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setDatabase(Database.POSTGRESQL);
    vendorAdapter.setGenerateDdl(true);
    vendorAdapter.setShowSql(true);

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("com.goode.business");
    factory.setDataSource(dataSource());
    factory.setJpaProperties(jpaProperties());

    return factory;
  }

  private Properties jpaProperties() {
    Properties properties = new Properties();
    properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
    properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
    properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
    return properties;
  }
  @Bean
  public PlatformTransactionManager transactionManager() {

    JpaTransactionManager txManager = new JpaTransactionManager();
    txManager.setEntityManagerFactory(entityManagerFactory().getObject());
    return txManager;
  }

}

application.properties

jdbc.driverClassName = org.postgresql.Driver
jdbc.url = jdbc:postgresql://localhost:5432/GoodE
jdbc.username = postgres
jdbc.password = postgres
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
hibernate.show_sql = true
hibernate.format_sql = true
email.username = xx //I replce real data to xx just to this post
email.password = xx
email.fullAddress = xx@xx.com
email.host = xx
email.port = xx

当我尝试从 SendEmail 控制台调用 send 方法时显示错误:

java.lang.NullPointerException: null

排队:

props.put("mail.smtp.host", 主机);

所以注解@Value 不会将任何值从 application.properties 注入到 SendEmail 中的私有变量中。这是为什么呢?

RootConfig.java 中,我使用了 @AutowiredEnvironment@PropertySource,但我在某处看到你只能在@Configuration 类中使用@PropertySource,所以我尝试找到另一种方法-> 我找到了@Value,但我不知道为什么来自 application.properties 的数据没有注入到变量中。 我把 PropertySourcesPlaceholderConfigurer 放在 SendEmail 中,因为我读到它是必要的。我不确定这是适合它的地方,但将它放在另一个类中,例如RootConfig 没有帮助。 你有什么建议我应该在哪里搜索错误?

【问题讨论】:

  • application.properties 绝对会拿起那个钥匙。你能给我们看看那个文件吗?
  • 添加到主帖。我不确定这是不是一个问题,因为连接到数据库的数据加载正常。
  • 好的 - 感谢您提供。通常不会在属性键和等号之间放置空格。鉴于这是您注意到 NPE 的唯一行,当您去调试它时,您是否看到任何其他属性没有通过?
  • 也许尝试将这些属性放在一个单独的属性文件中并使用@PropertySource({"classpath:persistence.properties"}) 加载它。看看有没有帮助。
  • 尝试从组件中删除这三个 lombok 注释。我怀疑它忽略了一些值注释,因为它看到了全参数构造函数或使用@Data 创建的设置器,而那些不会有值注释。

标签: java spring model-view-controller


【解决方案1】:

这一行: @PropertySource(value = { "classpath:application.properties" }) 是不必要的,因为默认情况下会选取来自 application.properties 的所有值。话虽如此,您也不需要PropertySourcesPlaceholderConfigurer

确保在调用send 方法时,您没有将SendEmail 类实例化为new SendEmail(),因为@Value 仅在spring 应用程序上下文中起作用。

您必须执行@Autowired 或构造函数注入(建议使用后者)。

还有这个: @ComponentScan(basePackages = {"com.goode.service", "com.goode.repository", "com.goode.controller", "com.goode.business", "com.goode"}) 可以用这个代替: @ComponentScan(basePackages = {"com.goode.*"})

【讨论】:

  • 完美运行。很高兴知道 @Value 只能在 spring 应用程序上下文中注入。也感谢其他建议。
猜你喜欢
  • 2021-11-24
  • 2022-12-15
  • 2019-03-18
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 2011-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多