我开始搜索很多并没有找到解决方案。这个问题在代码加载时会相当长,问题是在运行时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]]
答案 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;