春豆是null,@Autowire注射不起作用,出了什么问题?

时间:2016-02-21 08:32:20

标签: spring spring-mvc dependency-injection nullpointerexception autowired

我开始搜索很多并没有找到解决方案。这个问题在代码加载时会相当长,问题是在运行时DataSource对象为null。这是我尝试将dataSource bean添加到spring容器的两种方法。我想这里没有错。实际上是创建了bean。

package com.stubtech.eztaxi.eztaxiapp.config;

**imports
@Configuration
public class DBConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(DBConfig.class);

@Autowired
private Environment environment;

@Bean
public DataSource dataSource(){
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName(environment.getProperty("jdbc.driverClass"));
    dataSource.setUrl(environment.getProperty("jdbc.url"));
    dataSource.setUsername(environment.getProperty("jdbc.username"));
    dataSource.setPassword(environment.getProperty("jdbc.password"));
    return dataSource;
}

@Bean(name = "jndiDataSource")
public DataSource dataSourceJndi() {
    DataSource dataSource = null;
    try {
        JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup();
        jndiDataSourceLookup.setResourceRef(true);
        dataSource = jndiDataSourceLookup.getDataSource("jdbc/EZTaxiDB");
        LOGGER.debug("Created DS");
    } catch (Exception e) {
        LOGGER.error("No DS: " + e.getMessage());
    }
    return dataSource;
}
}

我已经使用.xml配置文件并使用以下类进行Web初始化:

public class WebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) throws ServletException {
    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(WebConfig.class);

    // Manage lifecycle of the rootContext
    container.addListener(new ContextLoaderListener(rootContext));

    DispatcherServlet dispatcherServlet = new DispatcherServlet(rootContext);
    ServletRegistration.Dynamic registration = container.addServlet("dispatcherServlet", dispatcherServlet);
    registration.setLoadOnStartup(1);
    registration.addMapping("/");

    DelegatingFilterProxy delegatingFilterProxy = new DelegatingFilterProxy("springSecurityFilterChain");
    container.addFilter("springSecurityFilterChain", delegatingFilterProxy).addMappingForUrlPatterns(null, false, "/*");
}
}

同时我尝试使用jjwt令牌进行自动化,这里是SecurityConfig:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

private final ITokenAuthService tokenAuthService;
private final UserDetailsService userDetailsService;
private final ISecretReader secretReader;

public SecurityConfig() {
    super(true);
    this.secretReader = new SecretReaderImpl();
    this.userDetailsService = new UserDetailsServiceImpl();
    this.tokenAuthService = new TokenAuthServiceImpl();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .exceptionHandling().and()
            .anonymous().and()
            .servletApi().and()
            .authorizeRequests()

            // Allow anonymous resource requests
            .antMatchers("/").permitAll()
            .antMatchers("/favicon.ico").permitAll()
            .antMatchers("**/*.html").permitAll()
            .antMatchers("**/*.css").permitAll()
            .antMatchers("**/*.js").permitAll()

            // Allow anonymous logins
            .antMatchers("/auth/**").permitAll()

            // All other request need to be authenticated
            .anyRequest().authenticated().and()

            // Custom Token based authentication based on the header previously given to the client
            .addFilterBefore(new StatelessAuthenticationFilter(tokenAuthService()),
                    UsernamePasswordAuthenticationFilter.class)
            .headers().cacheControl();
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService()).passwordEncoder(new BCryptPasswordEncoder());
}

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

@Bean
public UserDetailsService userDetailsService() {
    return userDetailsService;
}

@Bean
public ITokenAuthService tokenAuthService() {
    return tokenAuthService;
}

@Bean
public ISecretReader secretReader() {
    return secretReader;
}
}

我正在尝试使用servlet进行授权:

@Component
@WebServlet("/auth/login")
public class AuthenticationServlet extends HttpServlet { // implements ServletResponse {

    private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationServlet.class);

    private WebApplicationContext springContext;

    @Autowired
    private UserInfoDAOImpl userInfoDAO;

    @Autowired
    private AuthenticationManager authenticationManager;

    public void init(final ServletConfig config) throws ServletException {
        //this.authenticationManager = authenticationManager;
//        ApplicationContext context =
//                WebApplicationContextUtils.getRequiredWebApplicationContext(
//                        this.getServletContext());
//        authenticationManager = (AuthenticationManager) context.getBean("authenticationManagerBean");
        super.init(config);
        springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
        final AutowireCapableBeanFactory beanFactory = springContext.getAutowireCapableBeanFactory();
        beanFactory.autowireBean(this);
        LOGGER.debug("Initialised login servlet");
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            UserInfo user = userInfoDAO.getUserInfoById("testuser");
            String un = request.getParameter("un");
            String pw = request.getParameter("pw");
            Authentication authrequest = new UsernamePasswordAuthenticationToken(un, pw);
            Authentication result = authenticationManager.authenticate(authrequest);
            SecurityContextHolder.getContext().setAuthentication(result);
            LOGGER.info("Successfully authenticated. Security context contains: " +
                    SecurityContextHolder.getContext().getAuthentication());
        } catch (AuthenticationException e) {
            LOGGER.error("Authentication failed: " + e.getMessage());
        }
    }
}

最后这是有NullPointer的地方 - dataSource为null:

@Component
public class UserInfoDAOImpl implements IUserInfoDAO {

    private final static Logger LOGGER = LoggerFactory.getLogger(UserInfoDAOImpl.class);

    @Autowired
    private DataSource dataSource;

    public UserInfo getUserInfoById(String username) {
        LOGGER.debug("Get user is called");

        String sql = "SELECT u.username name, u.password pass, ur.rolename role FROM " +
                "users u INNER JOIN user_role ur on u.id=ur.userid WHERE " +
                "u.enabled = 1 and u.username = ?";

        UserInfo userInfo = null;
        try {
            userInfo = new JdbcTemplate(this.dataSource).queryForObject(sql, new Object[]{username},
                    (rs, rowNum) -> {
                        UserInfo user = new UserInfo();
                        user.setUsername(rs.getString("name"));
                        user.setPassword(rs.getString("pass"));
                        user.setRole(rs.getString("role"));
                        return user;
                    });
        } catch (Exception e) {
            LOGGER.error("Failed to fetch user: " + e.getMessage());
        }
        return userInfo;
    }
}

这是WebConfig:

@EnableWebMvc
@Configuration
@ComponentScan(basePackages = ("com.stubtech.eztaxi.eztaxiapp"))
@PropertySource("classpath:application.properties")
public class WebConfig extends WebMvcConfigurerAdapter {

    private static final Logger LOGGER = LoggerFactory.getLogger(WebConfig.class);

    @Autowired
    private ApplicationContext appContext;

    public WebConfig(){
        LOGGER.debug("_____APP_STARTED_____");
        LOGGER.debug("...");
    }
}

从应用初始化记录:

  org.springframework.jdbc.datasource.DataSourceUtils]]
  Fetching JDBC Connection from DataSource]]
  org.springframework.jdbc.datasource.DriverManagerDataSource]]
  org.springframework.jdbc.datasource.DataSourceUtils]]
  Returning JDBC Connection to DataSource]]
  Failed to fetch user: Property 'dataSource' is required]]
  Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@596ded4b: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,webConfig,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor,DBConfig,securityConfig,userDetailsServiceImpl,userInfoDAOImpl,authenticationServlet,dataSource,jndiDataSource,org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration,authenticationManagerBuilder,enableGlobalAuthenticationAutowiredConfigurer,org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration,delegatingApplicationListener,webSecurityExpressionHandler,springSecurityFilterChain,privilegeEvaluator,autowiredWebSecurityConfigurersIgnoreParents,org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration,objectPostProcessor,org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration,requestDataValueProcessor,authenticationManagerBean,userDetailsService,tokenAuthService,secretReader,org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration,mvcValidator,mvcUrlPathHelper,mvcViewResolver,mvcPathMatcher,httpRequestHandlerAdapter,requestMappingHandlerMapping,mvcContentNegotiationManager,viewControllerHandlerMapping,resourceHandlerMapping,defaultServletHandlerMapping,mvcConversionService,beanNameHandlerMapping,mvcResourceUrlProvider,mvcUriComponentsContributor,simpleControllerHandlerAdapter,requestMappingHandlerAdapter,handlerExceptionResolver]; root of factory hierarchy]]
  Registering bean definition for @Bean method com.stubtech.eztaxi.eztaxiapp.config.DBConfig.dataSource()]]
  Registering bean definition for @Bean method com.stubtech.eztaxi.eztaxiapp.config.DBConfig.jndiDataSource()]]
  Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@665a082b: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,webConfig,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor,DBConfig,securityConfig,userDetailsServiceImpl,userInfoDAOImpl,authenticationServlet,dataSource,jndiDataSource,org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration,authenticationManagerBuilder,enableGlobalAuthenticationAutowiredConfigurer,org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration,delegatingApplicationListener,webSecurityExpressionHandler,springSecurityFilterChain,privilegeEvaluator,autowiredWebSecurityConfigurersIgnoreParents,org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration,objectPostProcessor,org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration,requestDataValueProcessor,authenticationManagerBean,userDetailsService,tokenAuthService,secretReader,org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration,mvcValidator,mvcUrlPathHelper,mvcViewResolver,mvcPathMatcher,httpRequestHandlerAdapter,requestMappingHandlerMapping,mvcContentNegotiationManager,viewControllerHandlerMapping,resourceHandlerMapping,defaultServletHandlerMapping,mvcConversionService,beanNameHandlerMapping,mvcResourceUrlProvider,mvcUriComponentsContributor,simpleControllerHandlerAdapter,requestMappingHandlerAdapter,handlerExceptionResolver]; root of factory hierarchy]]
  Registered injected element on class [com.stubtech.eztaxi.eztaxiapp.service.impl.UserInfoDAOImpl]: AutowiredFieldElement for private javax.sql.DataSource com.stubtech.eztaxi.eztaxiapp.service.impl.UserInfoDAOImpl.dataSource]]
  Processing injected element of bean 'userInfoDAOImpl': AutowiredFieldElement for private javax.sql.DataSource com.stubtech.eztaxi.eztaxiapp.service.impl.UserInfoDAOImpl.dataSource]]
  Creating shared instance of singleton bean 'dataSource']]
  Creating instance of bean 'dataSource']]
  org.springframework.jdbc.datasource.DriverManagerDataSource]]
  Eagerly caching bean 'dataSource' to allow for resolving potential circular references]]
  Finished creating instance of bean 'dataSource']]
  Creating shared instance of singleton bean 'jndiDataSource']]
  Creating instance of bean 'jndiDataSource']]
  org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup]]
  org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup]]
  Eagerly caching bean 'jndiDataSource' to allow for resolving potential circular references]]
  Not strongly caching class [com.sun.gjc.spi.jdbc40.DataSource40] because it is not cache-safe]]
  Finished creating instance of bean 'jndiDataSource']]
  Autowiring by type from bean name 'userInfoDAOImpl' to bean named 'dataSource']]
  Returning cached instance of singleton bean 'dataSource']]
  Returning cached instance of singleton bean 'jndiDataSource']]
  org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource]]
  org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource]]
  org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource]]
  org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource]]
  org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource]]
  org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource]]
  org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource]]
  Rejected bean name 'dataSource': no URL paths identified]]
  Rejected bean name 'jndiDataSource': no URL paths identified]]
  org.springframework.jdbc.datasource.DataSourceUtils]]
  Fetching JDBC Connection from DataSource]]
  org.springframework.jdbc.datasource.DriverManagerDataSource]]
  org.springframework.jdbc.datasource.DataSourceUtils]]
  Returning JDBC Connection to DataSource]]
  Failed to fetch user: Property 'dataSource' is required]]

1 个答案:

答案 0 :(得分:0)

显然,您正在配置类中创建DataSource的两个不同的bean。但是在注射时你只是在做以下事情:

@Autowired
private DataSource dataSource;

问题是Spring不知道在这里注入两个DataSource Bean中的哪一个。你必须使用@Qualifier让Spring知道哪个Bean是Injected。

将其更改为以下内容:

@Autowired
@Qualifier("dataSource")
private DataSource dataSource;

或者,您可以使用单个@Resource替换两个注释,如下所示:

@Resource(name = "dataSource")
private DataSource dataSource;