解决自定义securityMetadataSource不能使用依赖注入的问题,nullpointer问题,空指针问题
2016-07-12 16:50
483 查看
spring3,spring security,MySecurityMetadataSource,自定义securityMetadataSource,依赖注入,注解,注入,空指针异常,nullpointer,service
解决自定义securityMetadataSource不能使用依赖注入的问题,nullpointer问题,空指针问题 我在配置spring3和Security3 的时候为了从数据库管理资源,自定义了securityMetadataSource,但是在类中使用依赖注入的话,加载applicationContext-security.xml的时候,会抛出使用依赖注入的那一行对象为null,是什么原因?
也就是说提示依赖注入resourcesServiceImpl是nullpointer!这里只贴出applicationContext-security.xml和MySecurityMetadataSource.java的代码。网上有很多谈到的解决方案,但是都没有解决实质问题。 这里给出我的解决方法,其实,如同异常所示:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating
bean with name'mySecurityMetadataSource' defined in file [E:\Program Files\Apache SoftwareFoundation\Tomcat6.0\webapps\testSpringSecure\WEB-INF\classes\com\test\security\MySecurityMetadataSource.class]:Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class[com.test.security.MySecurityMetadataSource]: Constructor threw exception;nested exception is java.lang.NullPointerException
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:997)
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:943)
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
atorg.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
atorg.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
atorg.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
atorg.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
atorg.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:322)
...53 more
Caused by: org.springframework.beans.BeanInstantiationException: Could not
instantiate bean class[com.test.security.MySecurityMetadataSource]: Constructor threw exception;nested exception is java.lang.NullPointerException
atorg.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:162)
atorg.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:76)
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:990)
...61 more
Caused by: java.lang.NullPointerException
atcom.test.security.MySecurityMetadataSource.loadResourceDefine(MySecurityMetadataSource.java:81)
atcom.test.security.MySecurityMetadataSource.<init>(MySecurityMetadataSource.java:51)
atsun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
atsun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
atsun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
atjava.lang.reflect.Constructor.newInstance(Constructor.java:513)
atorg.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147)
...63 more
问题出在com.test.security.MySecurityMetadataSource.loadResourceDefine(MySecurityMetadataSource.java:81)上面。
网上给出的大部分解决方法是在xml里面配置强制注入resourcesServiceImpl,但是这样做很不灵活,而且由于大部分代码都已经用了注解来配置注入,所以不建议使用xml再来配置注入。 那么究竟是什么原因呢?其实答案很简单,就是在MySecurityMetadataSource.java中应该把两个自定义构造器去掉。如同我在下面的注释所说:
不要使用自定义构造方法,否则会导致注入会出错?应该是因为构造器中调用了loadResourceDefine方法,先于service注入,所以抛出异常。
我们这里并不需要自定义构造器,因为在使用注解注入时,注入会自动进行,当你使用了自定义构造器,由于里面调用了loadResourceDefine();而构造器在注入发生前就被调用了,所以就会先执行loadResourceDefine();,此时注入还没进行,因而就会抛出空指针异常了。
applicationContext-security.xml:
<?xml version="1.0"encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/securityhttp://www.springframework.org/schema/security/spring-security-3.0.xsd">
<!--
<global-method-security pre-post-annotations="enabled"/> -->
<global-method-security secured-annotations="enabled" jsr250-annotations="enabled"></global-method-security>
<http access-denied-page="/access_denied.jsp" use-expressions="true" entry-point-ref="authenticationProcessingFilterEntryPoint">
<!-- 该路径下的资源不用过滤 -->
<intercept-url pattern="/js/**" filters="none"/>
<!-- <logout invalidate-session="true" logout-success-url="/login.jsp"/>-->
<logout invalidate-session="true" logout-url="/j_spring_security_logout"success-handler-ref="customLogoutSuccessHandler" />
<!-- 实现免登陆验证 -->
<remember-me />
<!--
<form-login login-page="/login.jsp"default-target-url="/frame.jsp"always-use-default-target="true"/>
-->
<session-management invalid-session-url="/login.jsp">
<concurrency-control max-sessions="100" error-if-maximum-exceeded="false"/>
</session-management>
<custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER" />
<custom-filter ref="securityFilter"before="FILTER_SECURITY_INTERCEPTOR"/>
</http>
<!-- 未登录的切入点 -->
<beans:bean id="authenticationProcessingFilterEntryPoint"class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl"value="/login.jsp"></beans:property>
</beans:bean>
<!-- 退出登录的切入点 -->
<beans:bean id="customLogoutSuccessHandler" class="com.test.security.CustomLogoutSuccessHandler">
</beans:bean>
<!-- 登录验证器 -->
<beans:bean id="loginFilter"
class="com.test.security.MyUsernamePasswordAuthenticationFilter">
<!-- 处理登录 -->
<beans:property name="filterProcessesUrl"value="/j_spring_security_check"></beans:property>
<beans:property name="authenticationSuccessHandler"ref="loginLogAuthenticationSuccessHandler"></beans:property>
<beans:property name="authenticationFailureHandler"ref="simpleUrlAuthenticationFailureHandler"></beans:property>
<beans:property name="authenticationManager"ref="myAuthenticationManager"></beans:property>
</beans:bean>
<beans:bean id="loginLogAuthenticationSuccessHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl"value="/index.jsp"></beans:property>
</beans:bean>
<beans:bean id="simpleUrlAuthenticationFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl"value="/login.jsp"></beans:property>
</beans:bean>
<!-- 认证过滤器 -->
<beans:bean id="securityFilter"class="com.test.security.MySecurityFilter">
<!-- 用户拥有的权限 -->
<beans:property name="authenticationManager" ref="myAuthenticationManager" />
<!-- 用户是否拥有所请求资源的权限 -->
<beans:property name="accessDecisionManager" ref="myAccessDecisionManager" />
<!-- 资源与权限对应关系 -->
<beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />
</beans:bean>
<!-- 实现了UserDetailsService的Bean
-->
<authentication-manager alias="myAuthenticationManager">
<authentication-provider user-service-ref="myUserDetailServiceImpl"/>
</authentication-manager>
</beans:beans>
MySecurityMetadataSource:
package com.test.security;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import com.test.bean.Resources;
import com.test.dao.IResourcesDao;
import com.test.service.IResourcesService;
//1 加载资源与权限的对应关系
@Component("mySecurityMetadataSource")
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
/*不要使用自定义构造方法,否则导致注入会出错?应该是构造器中调用了loadResourceDefine方法,先于service注入,所以抛出异常。
public MySecurityMetadataSource() {
loadResourceDefine();
}
//由spring调用
public MySecurityMetadataSource(IResourcesService resourcesServiceImpl) {
this.resourcesServiceImpl = resourcesServiceImpl;
loadResourceDefine();
}*/
@Resource
private IResourcesService resourcesServiceImpl;
private static Map<String, Collection<ConfigAttribute>> resourceMap = null;
public Collection<ConfigAttribute> getAllConfigAttributes() {
// TODO Auto-generated method stub
return null;
}
public boolean supports(Class<?> clazz) {
// TODO Auto-generated method stub
return true;
}
//加载所有资源与权限的关系
@PostConstruct
private void loadResourceDefine() {
if(resourceMap == null) {
resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
List<Resources> resources = this.resourcesServiceImpl.findAll();
//List<Resources> resources = new ArrayList();
for (Resources resource : resources) {
Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
//以权限名封装为Spring的security Object
ConfigAttribute configAttribute = new SecurityConfig(resource.getName());
configAttributes.add(configAttribute);
resourceMap.put(resource.getUrl(), configAttributes);
}
}
Set<Entry<String, Collection<ConfigAttribute>>> resourceSet = resourceMap.entrySet();
Iterator<Entry<String, Collection<ConfigAttribute>>> iterator = resourceSet.iterator();
System.out.println("MySecurityMetadataSource:loadResourceDefine()");
}
//返回所请求资源所需要的权限
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
System.out.println("MySecurityMetadataSource:getAttributes()");
String requestUrl = ((FilterInvocation) object).getRequestUrl();
System.out.println("requestUrl is " + requestUrl);
if(resourceMap == null) {
loadResourceDefine();
}
Collection<ConfigAttribute> c = resourceMap.get(requestUrl);
System.out.println("MySecurityMetadataSource Collection<ConfigAttribute>:"+c);
return c;
}
}
收藏于 2014-01-10
解决自定义securityMetadataSource不能使用依赖注入的问题,nullpointer问题,空指针问题 我在配置spring3和Security3 的时候为了从数据库管理资源,自定义了securityMetadataSource,但是在类中使用依赖注入的话,加载applicationContext-security.xml的时候,会抛出使用依赖注入的那一行对象为null,是什么原因?
也就是说提示依赖注入resourcesServiceImpl是nullpointer!这里只贴出applicationContext-security.xml和MySecurityMetadataSource.java的代码。网上有很多谈到的解决方案,但是都没有解决实质问题。 这里给出我的解决方法,其实,如同异常所示:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating
bean with name'mySecurityMetadataSource' defined in file [E:\Program Files\Apache SoftwareFoundation\Tomcat6.0\webapps\testSpringSecure\WEB-INF\classes\com\test\security\MySecurityMetadataSource.class]:Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class[com.test.security.MySecurityMetadataSource]: Constructor threw exception;nested exception is java.lang.NullPointerException
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:997)
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:943)
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
atorg.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
atorg.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
atorg.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
atorg.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
atorg.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:322)
...53 more
Caused by: org.springframework.beans.BeanInstantiationException: Could not
instantiate bean class[com.test.security.MySecurityMetadataSource]: Constructor threw exception;nested exception is java.lang.NullPointerException
atorg.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:162)
atorg.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:76)
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:990)
...61 more
Caused by: java.lang.NullPointerException
atcom.test.security.MySecurityMetadataSource.loadResourceDefine(MySecurityMetadataSource.java:81)
atcom.test.security.MySecurityMetadataSource.<init>(MySecurityMetadataSource.java:51)
atsun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
atsun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
atsun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
atjava.lang.reflect.Constructor.newInstance(Constructor.java:513)
atorg.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147)
...63 more
问题出在com.test.security.MySecurityMetadataSource.loadResourceDefine(MySecurityMetadataSource.java:81)上面。
网上给出的大部分解决方法是在xml里面配置强制注入resourcesServiceImpl,但是这样做很不灵活,而且由于大部分代码都已经用了注解来配置注入,所以不建议使用xml再来配置注入。 那么究竟是什么原因呢?其实答案很简单,就是在MySecurityMetadataSource.java中应该把两个自定义构造器去掉。如同我在下面的注释所说:
不要使用自定义构造方法,否则会导致注入会出错?应该是因为构造器中调用了loadResourceDefine方法,先于service注入,所以抛出异常。
我们这里并不需要自定义构造器,因为在使用注解注入时,注入会自动进行,当你使用了自定义构造器,由于里面调用了loadResourceDefine();而构造器在注入发生前就被调用了,所以就会先执行loadResourceDefine();,此时注入还没进行,因而就会抛出空指针异常了。
applicationContext-security.xml:
<?xml version="1.0"encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/securityhttp://www.springframework.org/schema/security/spring-security-3.0.xsd">
<!--
<global-method-security pre-post-annotations="enabled"/> -->
<global-method-security secured-annotations="enabled" jsr250-annotations="enabled"></global-method-security>
<http access-denied-page="/access_denied.jsp" use-expressions="true" entry-point-ref="authenticationProcessingFilterEntryPoint">
<!-- 该路径下的资源不用过滤 -->
<intercept-url pattern="/js/**" filters="none"/>
<!-- <logout invalidate-session="true" logout-success-url="/login.jsp"/>-->
<logout invalidate-session="true" logout-url="/j_spring_security_logout"success-handler-ref="customLogoutSuccessHandler" />
<!-- 实现免登陆验证 -->
<remember-me />
<!--
<form-login login-page="/login.jsp"default-target-url="/frame.jsp"always-use-default-target="true"/>
-->
<session-management invalid-session-url="/login.jsp">
<concurrency-control max-sessions="100" error-if-maximum-exceeded="false"/>
</session-management>
<custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER" />
<custom-filter ref="securityFilter"before="FILTER_SECURITY_INTERCEPTOR"/>
</http>
<!-- 未登录的切入点 -->
<beans:bean id="authenticationProcessingFilterEntryPoint"class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl"value="/login.jsp"></beans:property>
</beans:bean>
<!-- 退出登录的切入点 -->
<beans:bean id="customLogoutSuccessHandler" class="com.test.security.CustomLogoutSuccessHandler">
</beans:bean>
<!-- 登录验证器 -->
<beans:bean id="loginFilter"
class="com.test.security.MyUsernamePasswordAuthenticationFilter">
<!-- 处理登录 -->
<beans:property name="filterProcessesUrl"value="/j_spring_security_check"></beans:property>
<beans:property name="authenticationSuccessHandler"ref="loginLogAuthenticationSuccessHandler"></beans:property>
<beans:property name="authenticationFailureHandler"ref="simpleUrlAuthenticationFailureHandler"></beans:property>
<beans:property name="authenticationManager"ref="myAuthenticationManager"></beans:property>
</beans:bean>
<beans:bean id="loginLogAuthenticationSuccessHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl"value="/index.jsp"></beans:property>
</beans:bean>
<beans:bean id="simpleUrlAuthenticationFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl"value="/login.jsp"></beans:property>
</beans:bean>
<!-- 认证过滤器 -->
<beans:bean id="securityFilter"class="com.test.security.MySecurityFilter">
<!-- 用户拥有的权限 -->
<beans:property name="authenticationManager" ref="myAuthenticationManager" />
<!-- 用户是否拥有所请求资源的权限 -->
<beans:property name="accessDecisionManager" ref="myAccessDecisionManager" />
<!-- 资源与权限对应关系 -->
<beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />
</beans:bean>
<!-- 实现了UserDetailsService的Bean
-->
<authentication-manager alias="myAuthenticationManager">
<authentication-provider user-service-ref="myUserDetailServiceImpl"/>
</authentication-manager>
</beans:beans>
MySecurityMetadataSource:
package com.test.security;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import com.test.bean.Resources;
import com.test.dao.IResourcesDao;
import com.test.service.IResourcesService;
//1 加载资源与权限的对应关系
@Component("mySecurityMetadataSource")
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
/*不要使用自定义构造方法,否则导致注入会出错?应该是构造器中调用了loadResourceDefine方法,先于service注入,所以抛出异常。
public MySecurityMetadataSource() {
loadResourceDefine();
}
//由spring调用
public MySecurityMetadataSource(IResourcesService resourcesServiceImpl) {
this.resourcesServiceImpl = resourcesServiceImpl;
loadResourceDefine();
}*/
@Resource
private IResourcesService resourcesServiceImpl;
private static Map<String, Collection<ConfigAttribute>> resourceMap = null;
public Collection<ConfigAttribute> getAllConfigAttributes() {
// TODO Auto-generated method stub
return null;
}
public boolean supports(Class<?> clazz) {
// TODO Auto-generated method stub
return true;
}
//加载所有资源与权限的关系
@PostConstruct
private void loadResourceDefine() {
if(resourceMap == null) {
resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
List<Resources> resources = this.resourcesServiceImpl.findAll();
//List<Resources> resources = new ArrayList();
for (Resources resource : resources) {
Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
//以权限名封装为Spring的security Object
ConfigAttribute configAttribute = new SecurityConfig(resource.getName());
configAttributes.add(configAttribute);
resourceMap.put(resource.getUrl(), configAttributes);
}
}
Set<Entry<String, Collection<ConfigAttribute>>> resourceSet = resourceMap.entrySet();
Iterator<Entry<String, Collection<ConfigAttribute>>> iterator = resourceSet.iterator();
System.out.println("MySecurityMetadataSource:loadResourceDefine()");
}
//返回所请求资源所需要的权限
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
System.out.println("MySecurityMetadataSource:getAttributes()");
String requestUrl = ((FilterInvocation) object).getRequestUrl();
System.out.println("requestUrl is " + requestUrl);
if(resourceMap == null) {
loadResourceDefine();
}
Collection<ConfigAttribute> c = resourceMap.get(requestUrl);
System.out.println("MySecurityMetadataSource Collection<ConfigAttribute>:"+c);
return c;
}
}
收藏于 2014-01-10
相关文章推荐
- Linux软件安装包中devel与非devel包之间的区别
- WCF学习之旅—基于ServiceDebug的异常处理(十七)
- 【bzoj4027】 [HEOI2015]兔子与樱花
- Sum of Two Integers
- Drools 6.0 Hello World
- Maven详解之仓库------本地仓库、远程仓库、私服
- deep learning---利用caffe在vgg-face上finetuing自己的人脸数据
- 详解资源文件Drawable下面的shape标签
- 合金
- <a>标签跳转和执行js函数,href和onclick属性
- +function ($) { "use strict";}(window.jQuery);全面分析
- 「Unity」UGUI的Text实现首行缩进的办法
- iOS开发之指纹解锁
- jquery $.trim()方法使用介绍
- iOS开发中的Web Service
- FreeSwitch Lua Welcome IVR
- java8 Optional类用法解析
- STL关联式容器之红黑树
- poj 1442 优先队列
- 最大子段和