Java spring@Autowired给出NullPointerException
我正在用Hibernate学习Spring,并用简单的登录制作一个演示项目。我被@Autowired设置为NullPointerException所困扰。我没有得到它背后的正确原因,但我想这是因为Spring无法自己实例化bean 只有当我使用customAuthenticationProvider登录时才会出现问题。如果我使用默认的Java spring@Autowired给出NullPointerException,java,spring,spring-mvc,spring-security,Java,Spring,Spring Mvc,Spring Security,我正在用Hibernate学习Spring,并用简单的登录制作一个演示项目。我被@Autowired设置为NullPointerException所困扰。我没有得到它背后的正确原因,但我想这是因为Spring无法自己实例化bean 只有当我使用customAuthenticationProvider登录时才会出现问题。如果我使用默认的,用户名和密码为admin,代码运行正常 这是我的密码 web.xml <web-app xmlns="http://xmlns.jcp.org/xml/ns
,用户名和密码为admin,代码运行正常
这是我的密码
web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-security.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
</web-app>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven />
<context:component-scan base-package="com.ssb" />
<context:annotation-config />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/springHibernateDemo" />
<property name="username" value="root" />
<property name="password" value="admin" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.ssb.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<http pattern="/resources/**" security="none" />
<http auto-config="true" use-expressions="true">
<http-basic/>
<intercept-url pattern="/login" access="permitAll"/>
<intercept-url pattern="/**" access="isAuthenticated()" />
<form-login login-page="/login" default-target-url="/home"
authentication-failure-url="/login?error" login-processing-url="/j_spring_security_check"
username-parameter="username" password-parameter="password" />
<logout logout-success-url="/login?logout" logout-url="/j_spring_security_logout"/>
<!-- enable csrf protection -->
<csrf/>
</http>
<beans:bean id="customAuthenticationProvider"
class="com.ssb.components.CustomAuthenticationProvider">
</beans:bean>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
<authentication-provider ref="customAuthenticationProvider">
</authentication-provider>
</authentication-manager>
</beans:beans>
AuthServiceImpl.java
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
public AuthService authService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
authService.authenticateUser(authentication);
// it never gets to this line as authService is null
return new UsernamePasswordAuthenticationToken(authentication.getName(), "");
}
@Override
public boolean supports(Class<?> authentication) {
return true;
}
}
@Controller
public class HomeController {
@Autowired
HomeService homeService;
@Autowired
SessionFactory sessionFactory;
@RequestMapping(value="/home", method=RequestMethod.GET)
public String home(Model model){
User user = new User();
user.setName("test");
user.setPassword("test");
homeService.save(user);
return "home";
}
@RequestMapping(value= "/login", method=RequestMethod.GET)
public ModelAndView login(
@RequestParam(value = "error", required = false) String error,
@RequestParam(value = "logout", required = false) String logout) throws IOException {
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("login");
return model;
}
}
@Service
public class AuthServiceImpl implements AuthService{
@Autowired
HomeDao homeDao;
@Transactional
public void authenticateUser(Authentication authentication) {
homeDao.authenticateUser(authentication);
}
}
@Repository
public class HomeDao {
@Autowired
SessionFactory sessionFactory;
public void save(User user){
Session session = sessionFactory.getCurrentSession();
Roles role = (Roles) session.get(Roles.class, 1);
user.setRole_id(role);
session.save(user);
}
public void authenticateUser(Authentication authentication) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(User.class);
criteria.add(Restrictions.eq("username", authentication.getPrincipal().toString()));
criteria.add(Restrictions.eq("password", authentication.getCredentials().toString()));
@SuppressWarnings("unchecked")
List<User> result = criteria.list();
System.out.println(result);
}
}
HomeDao.java
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
public AuthService authService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
authService.authenticateUser(authentication);
// it never gets to this line as authService is null
return new UsernamePasswordAuthenticationToken(authentication.getName(), "");
}
@Override
public boolean supports(Class<?> authentication) {
return true;
}
}
@Controller
public class HomeController {
@Autowired
HomeService homeService;
@Autowired
SessionFactory sessionFactory;
@RequestMapping(value="/home", method=RequestMethod.GET)
public String home(Model model){
User user = new User();
user.setName("test");
user.setPassword("test");
homeService.save(user);
return "home";
}
@RequestMapping(value= "/login", method=RequestMethod.GET)
public ModelAndView login(
@RequestParam(value = "error", required = false) String error,
@RequestParam(value = "logout", required = false) String logout) throws IOException {
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("login");
return model;
}
}
@Service
public class AuthServiceImpl implements AuthService{
@Autowired
HomeDao homeDao;
@Transactional
public void authenticateUser(Authentication authentication) {
homeDao.authenticateUser(authentication);
}
}
@Repository
public class HomeDao {
@Autowired
SessionFactory sessionFactory;
public void save(User user){
Session session = sessionFactory.getCurrentSession();
Roles role = (Roles) session.get(Roles.class, 1);
user.setRole_id(role);
session.save(user);
}
public void authenticateUser(Authentication authentication) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(User.class);
criteria.add(Restrictions.eq("username", authentication.getPrincipal().toString()));
criteria.add(Restrictions.eq("password", authentication.getCredentials().toString()));
@SuppressWarnings("unchecked")
List<User> result = criteria.list();
System.out.println(result);
}
}
您正在将
spring security.xml
加载为spring根上下文,并且在此上下文中没有任何上下文:组件扫描
,因此在尝试在根上下文中使用@Autowired
bean时接收NPE是绝对正常的,该根上下文已加载到mvc上下文中,它是一个子上下文
您可以在以下答案中获得更多信息:
为了避免此类错误,我将执行以下操作:
dispatcherservlet.xml
中,只需在上下文中映射:组件扫描@Controller
映射的原型李>
例如:
<context:component-scan base-package="com.ssb.controller" />
<context:component-scan base-package="com.ssb.repositories" />
<context:component-scan base-package="com.ssb.services" />
同样,您应该将dispatcherservlet.xml
中定义的一些bean移动到spring security.xml
中李>
就这些:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/springHibernateDemo" />
<property name="username" value="root" />
<property name="password" value="admin" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.ssb.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
spring-security.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<context:component-scan base-package="com.ssb" />
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
<beans:property name="url"
value="jdbc:mysql://localhost:3306/springHibernateDemo" />
<beans:property name="username" value="root" />
<beans:property name="password" value="admin" />
</beans:bean>
<beans:bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="packagesToScan" value="com.ssb.model" />
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
</beans:prop>
<beans:prop key="hibernate.show_sql">true</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<beans:bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="sessionFactory" />
</beans:bean>
<http pattern="/resources/**" security="none" />
<http auto-config="true" use-expressions="true">
<http-basic />
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
<form-login login-page="/login" default-target-url="/home"
authentication-failure-url="/login?error" login-processing-url="/j_spring_security_check"
username-parameter="username" password-parameter="password" />
<logout logout-success-url="/login?logout" logout-url="/j_spring_security_logout" />
<!-- enable csrf protection -->
<csrf />
</http>
<beans:bean id="customAuthenticationProvider"
class="com.ssb.components.CustomAuthenticationProvider">
</beans:bean>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
<authentication-provider ref="customAuthenticationProvider">
</authentication-provider>
</authentication-manager>
</beans:beans>
更新
org.hibernate.dialogue.mysqldialogue
真的
尝试在dispatcher-servlet.xml的末尾放置上下文:component scan base package=“com.ssb”,它可能会起作用,因为在ioc容器中放置bean时需要依赖项,因此在创建AuthService bean时,需要在ioc容器中未创建的依赖项类。确保所有依赖项配置正确的顺序
Spring@Autowired
不能为null
,如果在这种情况下应用程序甚至无法启动。只有在xml中未设置注释处理context:component scan
或context:annotation config
或者您自己正在创建bean的新实例时,它才会为null
。在您的情况下,第一种情况类似。@M.Deinum请查看dispatcher-servlet.xml<代码>
就在那里。这是为DispatcherServlet
加载的上下文,而不是由ContextLoarListener
加载的上下文,它们与Bean(Factory)后处理器互不影响。
您是否传递了原型注释所在的确切包名。是的,我传递了确切的基本包“com.ssb”.