복붙노트

[SPRING] 비 싱글 톤 빈에서 캐스팅 된 스프링 프록시에서 BeanNotOfRequiredTypeException 수정?

SPRING

비 싱글 톤 빈에서 캐스팅 된 스프링 프록시에서 BeanNotOfRequiredTypeException 수정?

응용 프로그램 컨텍스트에서 Spring 빈을 가져 오는 것과 관련된 문제가 있습니다.

시도 할 때;

InnerThread instance = (InnerThread) SpringContextFactory.getApplicationContext().getBean("innerThread", InnerThread.class);

나는 얻다;

org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'innerThread' must be of type [com.generic.InnerThread], but was actually of type [$Proxy26]

getBean () 호출에서 지정된 클래스가 없으면 ClassCastException이 발생합니다 (아래에서 자세히 볼 수 있음).

InnerThread 빈은 다중 인스턴스가 필요하기 때문에 non-singleton으로 초기화됩니다. InnerThread 클래스는 또한 Thread를 확장합니다. 흥미로운 점은이 오류가 InnerThread와 동일한 방식으로 설정되는 OuterThread 내에 표시된다는 것입니다.

아래에 관련된 모든 코드 목록 / 스택 추적을 포함 시키려고했습니다. 더 많은 봄 경험을 가진 사람이 여기에서 무슨 일이 일어나는지 말해 줄 수 있습니까?

OuterThread.java 스 니펫 :

public class OuterThread extends Thread {
    private Queue<InnerThread> createInnerThreads() {
        Queue<InnerThread> threads = new ArrayBlockingQueue();

        ApplicationContext ctx = SpringContextFactory.getApplicationContext();
        int i = 0;
        for (SearchRule search : searches) {
            logger.debug("Number of times looped " + i++);
            //Seprated lines to get a better sense of what is going on
            Object proxy = ctx.getBean("innerThread", InnerThread.class);
            logger.debug(ReflectionToStringBuilder.toString(proxy));
            logger.debug("proxy.getClass(): " + proxy.getClass());
            logger.debug("proxy.getClass().getClassLoader(): " + proxy.getClass().getClassLoader());
            logger.debug("proxy.getClass().getDeclaringClass(): " + proxy.getClass().getDeclaringClass());
            logger.debug("InnerThread.class.getClassLoader(): " + InnerThread.class.getClassLoader());

            //---Exception here---
            InnerThread cst = (InnerThread) proxy;

            threads.add(cst);
        }
        return threads;
    }

    public static void main(String[] args) throws Exception {
        try {
            OuterThread instance = (OuterThread) SpringContextFactory.getApplicationContext().getBean("outerThread", OuterThread.class);
            instance.run();
        } catch (Exception ex) {
            logger.error("Fatal exception.", ex);
            throw ex;
        }
    }
}

SpringContextFactory.java:

public class SpringContextFactory {
    static final Logger logger = LoggerFactory.getLogger(SpringContextFactory.class);
    private static ApplicationContext ctx;
    private static final String DEFAULT_PATH = "META-INF/app-context.xml";

    public static ApplicationContext getApplicationContext() {
        return getApplicationContext(DEFAULT_PATH);
    }

    public static synchronized ApplicationContext getApplicationContext(String path) {
        if (ctx == null) return createApplicationContext(path);
        else return ctx;
    }

    private static ApplicationContext createApplicationContext(String path) {
        if (logger.isDebugEnabled()) logger.debug("Loading Spring Context...");
        ctx = new ClassPathXmlApplicationContext(path);
        if (logger.isDebugEnabled()) logger.debug("Spring Context Loaded");
        return ctx;
    }
}

app-context.xml :

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <!-- persistence context from separate jar -->
    <import resource="persistence-context.xml"/>

    <bean id="outerThread" class="com.generic.OuterThread" scope="prototype"/>
    <bean id="innerThread" class="com.generic.InnerThread" scope="prototype"/>

</beans>
2009-05-08 14:34:37,341 [main] DEBUG com.generic.OuterThread.init(OuterThread.java:59) - Initializing OuterThread object, com.generic.OuterThread@1c8fb4b[em=org.hibernate.ejb.EntityManagerImpl@e2892b,currentTime=java.util.GregorianCalendar[time=1241634874841,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2009,MONTH=4,WEEK_OF_YEAR=19,WEEK_OF_MONTH=2,DAY_OF_MONTH=6,DAY_OF_YEAR=126,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=2,HOUR_OF_DAY=14,MINUTE=34,SECOND=34,MILLISECOND=841,ZONE_OFFSET=-18000000,DST_OFFSET=3600000],maxConcurrentThreads=5,reconId=3,reportUsername=TEST,useOffset=false,username=removed,uuid=bf61494d-ff96-431c-a41f-1e292d0c9fbe,name={T,h,r,e,a,d,-,1},priority=5,threadQ=<null>,eetop=0,single_step=false,daemon=false,stillborn=false,target=<null>,group=java.lang.ThreadGroup[name=main,maxpri=10],contextClassLoader=sun.misc.Launcher$AppClassLoader@11b86e7,inheritedAccessControlContext=java.security.AccessControlContext@1524d43,threadLocals=<null>,inheritableThreadLocals=java.lang.ThreadLocal$ThreadLocalMap@2cbc86,stackSize=0,nativeParkEventPointer=0,tid=9,threadStatus=0,parkBlocker=<null>,blocker=<null>,blockerLock=java.lang.Object@a68fd8,stopBeforeStart=false,throwableFromStop=<null>,uncaughtExceptionHandler=<null>]
2009-05-08 14:34:37,341 [main] DEBUG org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.doJoinTransaction(ExtendedEntityManagerCreator.java:385) - No local transaction to join
2009-05-08 14:34:37,529 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.java:139) - Number of times looped 0
2009-05-08 14:34:37,529 [main] DEBUG org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:458) - Creating instance of bean 'searchThread' with merged definition [Root bean: class [com.generic.InnerThread]; scope=prototype; abstract=false; lazyInit=false; autowireCandidate=true; autowireMode=0; dependencyCheck=0; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [META-INF/app-context.xml]]
2009-05-08 14:34:37,545 [main] DEBUG com.generic.InnerThread.<init>(InnerThread.java:50) - Constructing InnerThread object, com.generic.InnerThread@1080876[em=<null>,coolScheme=<null>,coolUrl=<null>,date=<null>,error=<null>,millisecondsTaken=0,thresholdMet=false,reconId=0,result=-2,searchId=0,username=<null>,uuid=<null>,name={T,h,r,e,a,d,-,2},priority=5,threadQ=<null>,eetop=0,single_step=false,daemon=false,stillborn=false,target=<null>,group=java.lang.ThreadGroup[name=main,maxpri=10],contextClassLoader=sun.misc.Launcher$AppClassLoader@11b86e7,inheritedAccessControlContext=java.security.AccessControlContext@1524d43,threadLocals=<null>,inheritableThreadLocals=java.lang.ThreadLocal$ThreadLocalMap@3aef16,stackSize=0,nativeParkEventPointer=0,tid=10,threadStatus=0,parkBlocker=<null>,blocker=<null>,blockerLock=java.lang.Object@126c6ea,stopBeforeStart=false,throwableFromStop=<null>,uncaughtExceptionHandler=<null>]
2009-05-08 14:34:37,545 [main] DEBUG org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:203) - Returning cached instance of singleton bean 'entityManagerFactory'
2009-05-08 14:34:37,545 [main] DEBUG org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:203) - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
2009-05-08 14:34:37,560 [main] DEBUG org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource.getTransactionAttribute(AbstractFallbackTransactionAttributeSource.java:108) - Adding transactional method [report] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT]
2009-05-08 14:34:37,560 [main] DEBUG org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.buildAdvisors(AbstractAutoProxyCreator.java:494) - Creating implicit proxy for bean 'searchThread' with 0 common interceptors and 1 specific interceptors
2009-05-08 14:34:37,560 [main] DEBUG org.springframework.aop.framework.JdkDynamicAopProxy.getProxy(JdkDynamicAopProxy.java:113) - Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.generic.InnerThread@1080876]
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.java:141) - $Proxy26@1594a88[h=org.springframework.aop.framework.JdkDynamicAopProxy@1f0cf51]
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.java:142) - proxy.getClass(): class $Proxy26
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.java:143) - proxy.getClass().getClassLoader(): sun.misc.Launcher$AppClassLoader@11b86e7
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.java:144) - proxy.getClass().getDeclaringClass(): null
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.java:145) - InnerThread.class.getClassLoader(): sun.misc.Launcher$AppClassLoader@11b86e7
2009-05-08 14:34:37,591 [main] ERROR com.generic.OuterThread.run(OuterThread.java:101) - Exception in OuterThread, ending reconciliation.
java.lang.ClassCastException: $Proxy26 cannot be cast to com.generic.InnerThread
    at com.generic.OuterThread.createInnerThreads(OuterThread.java:148)
    at com.generic.OuterThread.run(OuterThread.java:65)
    at com.generic.OuterThread.main(OuterThread.java:170)

해결법

  1. ==============================

    1.@Configuration 클래스에 주석 달기

    @Configuration 클래스에 주석 달기

    @EnableAspectJAutoProxy(proxyTargetClass = true) 
    

    또한 다음 종속성을 추가해야합니다.

    <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.7.2</version>
    </dependency> 
    
  2. ==============================

    2.다시 한 번, 이것을 디버깅하는 데 많은 시간을 보낸 후에 StackOverflow에 게시 한 직후 답변을 찾았습니다.

    다시 한 번, 이것을 디버깅하는 데 많은 시간을 보낸 후에 StackOverflow에 게시 한 직후 답변을 찾았습니다.

    내 질문에서 빠뜨린 중요한 점은 InnerThread가 트랜잭션 방식을 가졌다는 것입니다 (미안하지만 관련성이 없다고 생각했습니다). OuterThread와 InnerThread의 중요한 차이점입니다.

    Spring 문서에서 :

    위의 내용을 내 구성에 추가하면 (위에서로드 된 persistance-context.xml에 기반 함) 문제를 해결하는 것으로 보입니다. 그러나 이것이 실제 솔루션과 대비되는 빠른 해결 방법 일 수 있다고 생각합니다.

    나는 여기에 몇 가지 더 깊은 이슈를 가지고 있다고 생각하는데, 그 중 하나는 내가 봄을 지나치게 복잡한 것처럼 혼동스럽게 생각한다는 것이다. 둘째로 Spring의 TaskExecutor를 사용하여 스레드를 시작해야한다. 세 번째 스레드는 Thread를 확장하는 대신 Runnable을 구현해야합니다 (아래의 SO 질문 참조).

    참고 사항

  3. ==============================

    3.이것은 단지 추측이지만 인터페이스 InnerThreadInterface를 만든 다음 InnerThread 클래스가 그것을 확장하도록하십시오.

    이것은 단지 추측이지만 인터페이스 InnerThreadInterface를 만든 다음 InnerThread 클래스가 그것을 확장하도록하십시오.

    그 후에는 다음을 수행 할 수 있어야합니다.

    InnerThreadInterface inner = ctx.getBean ( "innerThread", InnerThread.class);

  4. ==============================

    4.CGLIB를 참조하고 proxy-target-class = "true"설정을 사용했지만이 문제가 발생했습니다. 나는 ehcache를 결정했다 : 주석 태그는 비난했다. 다음 구성을 제거하면 나를 위해이 문제가 해결되었다. 다행히 ehcache 선언적 캐싱을 사용하지 않고 최대 절전 모드 2 캐싱을 사용할 수있었습니다.

    CGLIB를 참조하고 proxy-target-class = "true"설정을 사용했지만이 문제가 발생했습니다. 나는 ehcache를 결정했다 : 주석 태그는 비난했다. 다음 구성을 제거하면 나를 위해이 문제가 해결되었다. 다행히 ehcache 선언적 캐싱을 사용하지 않고 최대 절전 모드 2 캐싱을 사용할 수있었습니다.

    <ehcache:annotations>
        <ehcache:caching id="myCacheModel" cacheName="myCache"/>
        <ehcache:flushing id="myFlushModel" cacheNames="myCache" when="after"/>
    </ehcache:annotations> 
    
  5. ==============================

    5.나는 똑같은 문제가 있었다.

    나는 똑같은 문제가 있었다.

    위에 게시 된 내용 대신이 방법을 사용하면 정상적으로 작동합니다. proxy-target-class를 true로 설정할 필요가 없었습니다.이 클래스는 내 클래스 경로에없는 라이브러리를 더 필요로했습니다.

    InnerThreadInterface inner = (InnerThreadInterface)ctx.getBean("innerThread");
    
  6. ==============================

    6.이 문제를 해결하는 한 가지 방법은 실행 가능한 인터페이스를 확장하고 자신 만의 인터페이스를 생성하는 것입니다.

    이 문제를 해결하는 한 가지 방법은 실행 가능한 인터페이스를 확장하고 자신 만의 인터페이스를 생성하는 것입니다.

    public class MyInterface extends Runnable {
      // your own method declarations here
      void doSomething();
      ...
    }
    

    그런 다음 실행 가능 대신 인터페이스를 구현해야합니다.

    @Component("myInterface")
    @Scope("prototype")
         public class MyInterfaceImpl extends MyInterface {
    
              // your own method declarations here
              public void doSomething(){
              ...
              }
    
    
              // implement run from Runnable Interface
              @Transactional
              public void run(){
                    .....
              }
    
                 ...
            }
    

    이것은 잘 작동합니다 :

    ...
        MyInterface mynterface = SpringApplicationContext.getBean("myInterface", MyInterface.class);
    
        myInterface.doSomething();
      ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.submit(myInterface);
    ...
    
  7. ==============================

    7.이 문제를 처리하는 또 다른 방법은 인터페이스를 구현하고 봄 인터페이스를 요청하는 것입니다. 프록시는 인터페이스를 완벽하게 구현하고 캐스트에 문제가 없어야합니다.

    이 문제를 처리하는 또 다른 방법은 인터페이스를 구현하고 봄 인터페이스를 요청하는 것입니다. 프록시는 인터페이스를 완벽하게 구현하고 캐스트에 문제가 없어야합니다.

  8. ==============================

    8.DAO 인터페이스를 생성하고 SERVICE 클래스에 대한 DAO 인터페이스를 구현하고 applicationContext.xml 파일에 SERVICE 클래스의 설정 세부 사항을 제공한다. 즉, 스프링 설정 파일과 bean id를 사용하여 bean에 접근하고 인스턴스화 된 프록시의 인스턴스를 참조한다. DAO 인터페이스 개체 ... 완벽하게 작동합니다 ....

    DAO 인터페이스를 생성하고 SERVICE 클래스에 대한 DAO 인터페이스를 구현하고 applicationContext.xml 파일에 SERVICE 클래스의 설정 세부 사항을 제공한다. 즉, 스프링 설정 파일과 bean id를 사용하여 bean에 접근하고 인스턴스화 된 프록시의 인스턴스를 참조한다. DAO 인터페이스 개체 ... 완벽하게 작동합니다 ....

  9. from https://stackoverflow.com/questions/841231/fixing-beannotofrequiredtypeexception-on-spring-proxy-cast-on-a-non-singleton-be by cc-by-sa and MIT license