简体   繁体   中英

@Value not inject data from application.properties

I will show you a little code and then I will ask a question.

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

When I try call a send method from SendEmail console shows error:

java.lang.NullPointerException: null

in line:

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

So annotation @Value doesn't inject any value from application.properties to private variable in SendEmail. Why is that?

In RootConfig.java I used @Autowired , Environment and @PropertySource but I read somewhere that you can use @PropertySource only in @Configuration class so I tried find another way -> I found @Value, but I have no idea why data from application.properties are not injecting to variable. I put PropertySourcesPlaceholderConfigurer in SendEmail because I read it's necessary. I am not sure this is the right place for it but placing this in another class eg RootConfig didn't help. May you have any advice where should I search for bug?

This line: @PropertySource(value = { "classpath:application.properties" }) is unnecessary because all values from application.properties are picked up by default. That being said, you also don't need PropertySourcesPlaceholderConfigurer for that.

Make sure that when calling your send method, that you are not instantiating your SendEmail class as new SendEmail() because that will not work as @Value works only inside of the spring application context.

You must either do an @Autowired or constructor injection (the latter being recommended).

Also this: @ComponentScan(basePackages = {"com.goode.service", "com.goode.repository", "com.goode.controller", "com.goode.business", "com.goode"}) Can be replaced by this: @ComponentScan(basePackages = {"com.goode.*"})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM