Web Project에다가 Spring MVC를 적용하는 과정에서 web.xml 에 `Listener`를 추가하고 서버를 실행시키면 아래의 메시지가 출력한다.

  
2월 04, 2013 2:50:09 오후 org.apache.catalina.core.StandardContext listenerStop
심각: Exception sending context destroyed event to listener instance of class org.springframework.web.context.ContextLoaderListener
java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext
	at org.springframework.context.support.AbstractRefreshableApplicationContext.getBeanFactory(AbstractRefreshableApplicationContext.java:172)
	at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1071)
	at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1045)
	at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:993)
	at org.springframework.web.context.ContextLoader.closeWebApplicationContext(ContextLoader.java:548)
	at org.springframework.web.context.ContextLoaderListener.contextDestroyed(ContextLoaderListener.java:142)
	at org.apache.catalina.core.StandardContext.listenerStop(StandardContext.java:4831)
	at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5478)
	at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:160)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
	at java.util.concurrent.FutureTask.run(FutureTask.java:166)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
	at java.lang.Thread.run(Thread.java:722)


 

 발생원인

 

ContextLoaderListener 을 Listener로 등록해두면, 웹 애플리케이션이 시작할 때 자동으로 루트 애플리케이션 컨텍스트를 만들고 초기화를 한다. 디폴트Default로 XmlWebApplicationContext를 애플리케이션 컨텍스트 클래스가 지정되고 /WEB-INF/applicationContext.xml을 탐색한다. 이때, applicationContext.xml 파일을 찾지 못하면서 발생한다.


 

 해결방법

 

1. /WEB-INF/applicationContext.xml 생성 및 설정

2. web.xml 내에  <context-param></context-param> 으로 ~Context.xml 을 지정

  

        contextConfigLocation
        /WEB-INF/spring/appServlet/applicationContext.xml


위의 두 가지 방법 중 하나를 선택해서 처리하면 된다.




DispatcherServlerDI전략.mm



토비의 스프링 3

저자
이일민 지음
출판사
에이콘출판 | 2010-08-24 출간
카테고리
컴퓨터/IT
책소개
스프링 프레임워크 3 기초 원리부터 고급 실전활용까지 완벽 가이...
가격비교 글쓴이 평점  


  오늘 회사 동료가 알려준 방법인데, 꽤 유용할 것 같아서 이렇게 기록으로 남긴다.


  
package dreaminfra.ipams.web.assessment;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;

@Controller
@SessionAttributes({"simpleForm"})
@RequestMapping("/simple")
public class SimpleController {

    private final static String SIMPLE_FORM = "simpleForm";
    
    /**
     *   컨트롤러에서 @SessionAttribute({"simpleForm"}) 으로 선언한 simpleForm을 초기화하여
     * Session에서 유지하기 위해 반드시 구현해줘야 하는 부분이다.
     * @return
     */
    @ModelAttribute(SIMPLE_FORM)
    public SimpleForm createSimpleForm() {
        return new SimpleForm();
    }
    
    @RequestMapping(value="/request", method=RequestMethod.GET)
    public String request(Model model) {
        /**
         * Session에 SIMPLE_FORM을 생성하여 등록한다.
         */
        model.addAttribute(SIMPLE_FORM, new SimpleForm());
        
        return "/simple/response";
    }

    @RequestMapping(value="/response", method=RequestMethod.POST)
    public String response(@ModelAttribute(SIMPLE_FORM) SimpleForm form, SessionStatus status) {
        /**
         * Session 에 등록된 SimpleForm 은 SessionStatus.setComplete()을 실행하기 전까지는
         * Session에서 내부의 데이터를 유지하게 된다. SessionStatus.setComplete()을 실행하면
         * Controller에서 선언해둔 SessionAttribute에 등록된 form이 초기화된다. 
         */
        status.setComplete();
        
        return "redirect:/simple/request";
    }
    
    class SimpleForm {
        
        private String name;
        private String nickName;
        
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getNickName() {
            return nickName;
        }
        public void setNickName(String nickName) {
            this.nickName = nickName;
        }
    }
}


위에서 중요한 것은 Contoller 에서 선언한

SessionAttributes({"simpleForm"})

...

@ModelAttribute(SIMPLE_FORM)
    public SimpleForm createSimpleForm() {
        return new SimpleForm();
    }

...

model.addAttribute(SIMPLE_FORM, new SimpleForm());

...

session.setComplete()

부분이다.





Hibernate 를 사용하다가

HibernateException – A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance

의 오류를 발견했다. 인터넷을 뒤지다가 이에 대한 해결책을 찾아내었다.


본문을 보면 이런 내용이 나온다.

Your likely problem

Looks like you have a Parent entity and a Child entity. The Parent has a collection of Child entities with cascade=”all-delete-orphan”.

You are setting a new collection via the setter thus leaving the original collection unreferenced by the Parent entity. This doesn’t fly well with Hibernate and leaves it confused about what to do.

parent.setChilden(new HashSet<Child>()); // This won’t work. Could be an ArrayList too.

parent.getChildren().clear(); // There, fixed that!

So generally speaking, just clear out the old collection, rather than dereferencing it and creating a new one.

정리를 해보면, 필드에 새로 생성된 빈 Set 객체를 넣으려고 할 때 문제가 발생을 하는데,

초기화하려고 하는 Set 객체에서 clear() 메소드를 호출해주면 된다는 것이다. 


관계정의 옵션으로 

orphanRemoval=true, cascade=CascadeType.ALL

의 관계가 주어졌을 때 나타나는 증상으로 보인다.

<openjpa-2.1.1-r422266:1148538 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: Attempt to cast instance "...EntityItem@bbef5e8" to PersistenceCapable failed.  Ensure that it has been enhanced.

FailedObject: ...EntityItem@bbef5e8

at org.apache.openjpa.kernel.BrokerImpl.assertPersistenceCapable(BrokerImpl.java:4631)

at org.apache.openjpa.kernel.BrokerImpl.persistInternal(BrokerImpl.java:2610)

at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2555)

at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2538)

at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2442)

at org.apache.openjpa.kernel.DelegatingBroker.persist(DelegatingBroker.java:1077)

at org.apache.openjpa.persistence.EntityManagerImpl.persist(EntityManagerImpl.java:715)

...

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)

at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)

at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)

at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)

at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)

at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)

at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)

at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)

at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)

at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)

at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)

at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)

at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)

at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)

at org.junit.runners.ParentRunner.run(ParentRunner.java:236)

at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)

at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)



[해결책]

persistence.xml 에 Item들을 추가하세요.

+ Recent posts