GVKun编程网logo

spring autowired时发生异常情况(spring对异常的处理)

29

在本文中,我们将详细介绍springautowired时发生异常情况的各个方面,并为您提供关于spring对异常的处理的相关解答,同时,我们也将为您带来关于Quartz定时器+Spring+@Auto

在本文中,我们将详细介绍spring autowired时发生异常情况的各个方面,并为您提供关于spring对异常的处理的相关解答,同时,我们也将为您带来关于Quartz定时器+Spring + @Autowired注入 空指针异常、Shiro+Struts2+Spring3 加上 @RequiresPermissions 后 @Autowired 失效、spring @Autowired map、Spring @Autowired 和 @Resource的有用知识。

本文目录一览:

spring autowired时发生异常情况(spring对异常的处理)

spring autowired时发生异常情况(spring对异常的处理)

spring beanFactory那些就不说了,这次发生这个异常纠结好了好久,网上找了很多资料看,终于发现问题。

自动装配bean注入的时候,如果Spring配置定义了aop声明式事务,类似如下方式

<aop:config>
  <aop:pointcut id="serviceMethods2"
   expression="execution(public * net.villion.framework..*(..))" />
  <aop:advisor advice-ref="txAdvice2" pointcut-ref="serviceMethods2" />
 </aop:config>

那么@autowire注入bean的时候,会采用代理的模式注入Proxy,如果是接口定义的注入属性对象没有问题,如果是实体bean,那么就会有java.lang.ClassCastException.或者报类似这个 org.springframework.beans.TypeMismatchException: Failed to convert property value of type [com.sun.proxy.$Proxy ? implements .....错误。

以前使用好好的,我也没注意定义aop事务时,把包路径设置得太大了,覆盖了全部,导致注入出现异常情况。

给自己一个教训,这次找了好久,发文希望网上能够给大伙儿一个直接找到问题的地方。

Quartz定时器+Spring + @Autowired注入 空指针异常

Quartz定时器+Spring + @Autowired注入 空指针异常

 

 

在Quartz的定时方法里引用@Autowired注入Bean,会报空指针错误

 

 

解决办法:

第一种方法:(推荐,简单,亲测可行)

使用@Resource(name="指定要注入的Bean"),代替@Autowired即可,指定了要注入的Bean名字,就能找到该Bean,就不会空指针了。

 

@Resource(name = "deviceStateProducerService")
private DeviceStateProducerService deviceStateProducerService;

 

 

示例代码:

看下面红色字体部分

 代码

@Service("microDeviceStateService")
public class MicroDeviceStateServiceImpl implements MicroDeviceStateService {
    
    @Resource(name = "deviceStateProducerService")
    private DeviceStateProducerService deviceStateProducerService;
    
    @Scheduled(cron="0/10 * * * * * ?")
    @Lazy(false)
    public void pingDeviceState() {
        boolean isSuccess = PingUtils.ping("127.0.0.1", 4, 1000);
        MicroDeviceState microDeviceState = new MicroDeviceState();
        if(!isSuccess) {
            logger.debug("连接设备状态失败!");
            microDeviceState.setDeviceState("1");
        }else {
            microDeviceState.setDeviceState("0");
        }
        
        microDeviceState.setDeviceFlag("0");
        microDeviceState.setIp("127.0.0.1");
        DeviceStateBase deviceStateBase = new DeviceStateBase();
        BeanUtils.copyProperties(microDeviceState, deviceStateBase);
        deviceStateProducerService.deviceStateSender(deviceStateBase);
    }
    
    

}

 有的定时器不生效,在类上加注解@EnableScheduling(spring自带的定时任务功能)

 

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"   
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:task="http://www.springframework.org/schema/task"     
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd         
     http://www.springframework.org/schema/context 
      http://www.springframework.org/schema/context/spring-context-3.1.xsd 
     http://www.springframework.org/schema/task 
     http://www.springframework.org/schema/task/spring-task-3.2.xsd" 
     default-lazy-init="true">  


  
    <task:scheduler id="scheduler" pool-size="10" />  
    <task:executor id="executor" keep-alive="3600" pool-size="100-200" 
    queue-capacity="500" rejection-policy="CALLER_RUNS" /> 
    <task:annotation-driven executor="executor" scheduler="scheduler" />
    <!-- 注解配置定时器 -->
    <context:annotation-config /> 
     <!-- spring扫描注解的配置(要扫描的包,即定时器所在包) -->
     <context:component-scan base-package="com.zit.adapter.camera.CameraListener" />
     
</beans>

 

 

 

 

 

第二种方法:(也可行,不推荐)

使用Spring原生获取Bean的方法 取代 @Autowired注入,同时,不要与定时方法在同一个类

 

示例代码:

注解方式写了一个定时方法,方法里需要引用Dao层,插入数据库,

直接@Autowired会报空指针异常,做出如下红色字体改动

public class FTPUtil{

//    @Autowired
//    MicroCameraPassRecordDao microCameraPassRecordDao;

    private static MicroCameraPassRecordDao microCameraPassRecordDao = null;
    
    使用Spring获取注入bean
    static {
        microCameraPassRecordDao = 
                (MicroCameraPassRecordDao) SpringContextUtils.getApplicationContext().getBean("microCameraPassRecordDao");
    }



    /**
    * 定时从FTP下载图片到本地,在这个方法里调用别的Dao层的方法
    */
    @Scheduled(cron="0/20 * * * * * ?")
    @Lazy(false)
    public synchronized void service() {
        FTPUtil ftpUtil = new FTPUtil();
        boolean isConnect = ftpUtil.connectServer();
        //从FTP下载到工程file下
        boolean flag = ftpUtil.download(getFtpPath());
        
        //引用注入Bean,插入数据库
        MicroCameraPassRecord cameraRecord = new MicroCameraPassRecord();
        cameraRecord.setCameraId(deviceID);
        cameraRecord.setAddTime(System.currentTimeMillis());
        microCameraPassRecordDao.insert(cameraRecord);
        
    }
    
}

 getBean(引用类名,开头字母小写)

 

 

 SpringContextUtils

Spring获取Bean的工具类:


package com.zit.util;

import java.util.Map;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;


@SuppressWarnings({ "rawtypes", "unchecked" })
@Service("springContextUtils")
public class SpringContextUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;
     
    public void setApplicationContext(ApplicationContext arg0)
            throws BeansException {
        applicationContext = arg0;
    }
 
    /**
     * 获取applicationContext对象
     * @return
     */
    public static ApplicationContext getApplicationContext(){
        return applicationContext;
    }
     
    /**
     * 根据bean的id来查找对象
     * @param id
     * @return
     */
    public static Object getBeanById(String id){
        return applicationContext.getBean(id);
    }
     
    /**
     * 根据bean的class来查找对象
     * @param c
     * @return
     */
    public static Object getBeanByClass(Class c){
        return applicationContext.getBean(c);
    }
     
    /**
     * 根据bean的class来查找所有的对象(包括子类)
     * @param c
     * @return
     */
    public static Map getBeansByClass(Class c){
        return applicationContext.getBeansOfType(c);
    }

}

 

Shiro+Struts2+Spring3 加上 @RequiresPermissions 后 @Autowired 失效

Shiro+Struts2+Spring3 加上 @RequiresPermissions 后 @Autowired 失效

今天一 iteye 网页在问答频道提问【Shiro+Struts2+Spring3 加上 @RequiresPermissions 后 @Autowired 失效】,记录一下。

 

问题:

 

@ParentPackage("all") 
@Namespace("/project") 
public class ProjectAction extends BaseAction { 
public final static Logger logger = LoggerFactory 
.getLogger(ProjectAction.class); 

@Autowired(required=true) 
private ProjectService projectService;

 如上代码 @Autowired 注入不了

 

 

分析:

1、首先从如上代码可以看出 走的是 struts2 注解,而且使用了 struts2 convention 插件,这个插件会扫描如下配置的 actionPackages 寻找 action

 

<filter> 
        <filter-name>struts2</filter-name> 
        <filter-classfilter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class> 
        <init-param> 
<param-name>actionPackages</param-name> 
<param-value>cn.javass</param-value> 
</init-param>

 

 

2、但此时并没有把 action 交给 spring,

3、接下来,因为集成了 spring(有 struts2-spring-plugin),所以要使用 StrutsSpringObjectFactory 创建 bean,代码分析

 

@Override 
    public Object buildBean(String beanName, Map<String, Object> extraContext, boolean injectInternal) throws Exception { 
        Object o; 
        
        if (appContext.containsBean(beanName)) { 
            o = appContext.getBean(beanName); //拿不到bean 
        } else { 
            Class beanClazz = getClassInstance(beanName); 
            o = buildBean(beanClazz, extraContext); //所以创建了一个 
        } 
        if (injectInternal) { 
            injectInternalBeans(o); 
        } 
        return o; 
    }

 

/** 
     * @param clazz 
     * @param extraContext 
     * @throws Exception 
     */ 
    @Override 
    public Object buildBean(Class clazz, Map<String, Object> extraContext) throws Exception { 
        Object bean; 

        try { 
            // Decide to follow autowire strategy or use the legacy approach which mixes injection strategies 
            if (alwaysRespectAutowireStrategy) {//默认false 
                // Leave the creation up to Spring 
                bean = autoWiringFactory.createBean(clazz, autowireStrategy, false); 
                injectApplicationContext(bean); 
                return injectInternalBeans(bean); 
            } else { 
                bean = autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false); //只走构造器注入 
                bean = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName()); 
                // We don''t need to call the init-method since one won''t be registered. 
                bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName()); 
                return autoWireBean(bean, autoWiringFactory); 
            } 
        } catch (UnsatisfiedDependencyException e) { 
            if (LOG.isErrorEnabled()) 
                LOG.error("Error building bean", e); 
            // Fall back 
            return autoWireBean(super.buildBean(clazz, extraContext), autoWiringFactory); 
        } 
    }

 

 我们在 shiro 里使用如下代码 去代理 shiro 的代理:

 

<bean id="proxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true"/>
    </bean>

    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

 

 

//StrutsSpringObjectFactory 的如下代码将执行处理器的预处理

bean = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName());

 

//DefaultAdvisorAutoProxyCreator 的 postProcessBeforeInstantiation:将去完成代理 bean 因此此时将返回代理 Bean

 

// 接着 StrutsSpringObjectFactory 的 autoWireBean (bean, autoWiringFactory); 进行注入 所以此时注入到的是代理对象,因此如果字段注入 将注入不了。

 

 

解决方案

 

1、不使用 actionPackages   而是 在类上加  @Controller @Scope 完全走 spring  

2、使用 setter 注入 而不是字段 如 

  private ProjectService projectService; 

 

  @Autowired(required=true) 

  public void setProjectService() { 

  } 

 

 

spring @Autowired map

spring @Autowired map

 注入map,平常一般不会这么做,今天在写一个demo时,有如下一段注入代码:

map bean 的创建

@Bean(name="userMap")
public Map<Long, User> userMap() {
    return new ConcurrentHashMap<Long, User>();
}
// 注入
@Autowired
@Qualifier("userMap")
private Map<Long, User> userMap;

怕出错,我还特意加了Qualifier限定符,但是spring 容器就起不来了,异常如下,大概意思就是map的key要是String类型才行:

Caused by: org.springframework.beans.FatalBeanException: Key type [class java.lang.Long] of map [java.util.Map] must be assignable to [java.lang.String]

原因如下:org.springframework.beans.factory.support.DefaultListableBeanFactory中的一段代码

Class<?> keyType = descriptor.getMapKeyType();
            if (keyType == null || !String.class.isAssignableFrom(keyType)) {
                if (descriptor.isRequired()) {
                    throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
                            "] must be assignable to [java.lang.String]");
                }
                return null;
            }


用set 方法也不行。但是使用如下方法却奏效了:

@Resource(name = "userMap")
private Map<Long, User> userMap;



Spring @Autowired 和 @Resource

Spring @Autowired 和 @Resource

@Autowired

@Autowired 注释首先根据 Bean 名称匹配,如果找不到再根据类型匹配

@Resource

默认使用类型匹配,但是可以指定名称 @Resource(name = "BeanName")

示例

@ComponentScan
@Configuration
public class AutowiredDemo {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AutowiredDemo.class);
        Action action = applicationContext.getBean(Action.class);
        action.handle();
    }
}

@Component
class LocalService implements Service {
    @Override
    public void process() {
        System.out.println("local process");
    }
}

@Component
class RemoteService implements Service {
    @Override
    public void process() {
        System.out.println("remote process");
    }
}

@Component
class Action {

    // 正确的,根据 LocalService 的类型可以唯一匹配到一个 Bean
    @Autowired
    private LocalService localService1;
    
    // 错误的,根据 localService1 这个名称无法匹配到一个 Bean
    // 根据 Service 的类型匹配到了两个 Bean,不唯一,所以也是错误的
    @Autowired
    private Service localService1;
    
    // 正确的,根据 localService 的名称可以匹配到唯一的 Bean
    @Autowired
    private Service localService;
    
    // 正确的,Resource 在不指定名称的时候使用类型匹配
    @Resource
    private LocalService abc;

    // 正确的,Resource 可以指定名称
    @Resource(name = "localService")
    private Service localService1;

    public void handle() {
        localService1.process();
    }
}

关于spring autowired时发生异常情况spring对异常的处理的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于Quartz定时器+Spring + @Autowired注入 空指针异常、Shiro+Struts2+Spring3 加上 @RequiresPermissions 后 @Autowired 失效、spring @Autowired map、Spring @Autowired 和 @Resource的相关知识,请在本站寻找。

本文标签: