스프링xxfactory에 관하여.getBeanByType

5884 단어 factory
프로젝트 개발 과정에서 jvm에서 메모리를 회수할 수 없는 문제가 발생하여 마지막old구역은 100%를 차지하고 서버는 시간 초과 응답이 느리며 마지막에 자동으로 리셋됩니다...
 
jstack을 통해 6~700개의 스레드가 모두 막힌 상태임을 알 수 있습니다: BLOCKED
 
 
"resin-tcp-connection-*:8080-2401" daemon prio=10 tid=0x00002aab3df66000 nid=0x1693 waiting for monitor entry [0x00002aac50f09000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:180)
        - waiting to lock <0x00002aaabe5fd790> (a java.util.concurrent.ConcurrentHashMap)
        at org.springframework.beans.factory.support.AbstractBeanFactory.isTypeMatch(AbstractBeanFactory.java:415)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:223)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:303)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:297)
        at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:941)
        at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:224)
        at org.springframework.beans.factory.BeanFactoryUtils.beanOfTypeIncludingAncestors(BeanFactoryUtils.java:309)

 
 
구체적인 오류는 위에서 보십시오.spring의 원본 코드를 보았습니다
 
 
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory singletonFactory = (ObjectFactory) this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}
 
 
 
인터넷상에서 이것은 스프링의 결함이지만 최신 버전까지 복구되지 않았다.구체적으로 URL과 같습니다.
https://jira.springsource.org/browse/SPR-6870
 
 
스프링에서 스프링 용기 관리를 받는 Bean은 getBeanByName or getBeanByType을 통해
그 중에서 전자에서 얻을 수 있는 beanspring은 캐시를 추가한 것이고, getBeanBy Type은 매번 다시 생성한다. (사실은 나도 그의 원본 코드를 깊이 연구한 적이 없다)
 
 
하지만 나는 테스트를 하나 했다.
 
long startTime = System.currentTimeMillis();
		User user3 = null;
		for(int i=0; i<100000; i++) {
			user3 = BeanFactory.getBean("user");
			user3.print();
		}
		
		long endTime = System.currentTimeMillis();
		
		System.out.println("getBeanByName spend time :" + (endTime - startTime) + "ms");
		System.out.println("current momory:" + SprintTest.getUsedMemory());
		User user4 = null;
		for(int i=0; i<100000; i++) {
			user4 = BeanFactory.getBean(User.class);
			user4.print();
		}
		
		long end = System.currentTimeMillis();
		System.out.println("getBeanBytype spend time :" + (end - endTime) + "ms");
		System.out.println("current momory:" + SprintTest.getUsedMemory());
 
 
 
 
Factory 방법:
 
	@SuppressWarnings("unchecked")
	public static <T> T getBean(final String name) {
		return (T) ctx.getBean(name);
	}
	
	
	public static <T> T getBean(final Class<T> clazz) {
		return clazz.cast(BeanFactoryUtils.beanOfTypeIncludingAncestors(ctx, clazz));
	}
 
 
 
 
 
결과는 다음과 같습니다.
 
 
getBeanByName spend time :86ms
current momory:899560
getBeanBytype spend time :773ms
current momory:1576440
 
 
 
충격적이야...시간은 수량급의 차이이고 공간도 큰 차이가 있다.
get Bean By Type을 최대한 적게 사용하도록 권장합니다. 꼭 필요하면 인위적인 캐시를 추가해서 이런 성능 문제를 해결할 수 있습니다. 이런 버그가 발생하지 않도록 최대한 적게 사용하세요.
 
 
그 밖에 또 다른 문제를 제기했다. 어떤 학우들은 Util에서 Sprint 관리의 종류를 인용했다. 보통 Util의 방법은 정적이다. 그 자체가 Sprint 용기의 관리 범위 안에 있지 않다. 그러면 어떻게 이 방법을 해결할 수 있겠는가. Sprng 공장으로 bean을 얻을 수 있다.
 
 
public class BeanFactory implements ApplicationContextAware {
	
	private static ApplicationContext ctx;
	
	private static BeanFactory singleton; 
	
	public BeanFactory() {
	       singleton = this;
	}
	
	public static BeanFactory getInstance(){
		return singleton;
	}
	
	public void setApplicationContext(ApplicationContext ctx)
			throws BeansException {
		BeanFactory.ctx = ctx;
	}
	
	@Autowired
	private User user;
	
	public User getUser() {
		return user;
	}
	
	@SuppressWarnings("unchecked")
	public static <T> T getBean(final String name) {
		return (T) ctx.getBean(name);
	}
	
	
	public static <T> T getBean(final Class<T> clazz) {
		return clazz.cast(BeanFactoryUtils.beanOfTypeIncludingAncestors(ctx, clazz));
	}
 
 
 
 
BeanFactory를 통해 가능합니다.getInstance().getBean("name")의 방법으로 이루어집니다.
 
Spring에서 관리하는 bean에서 다른 bean을 호출하면 간단하거나 Spring의 @Autowired를 통해 주입하거나 set를 통해 주입해도 됩니다.
 
 
 
 
 
 

좋은 웹페이지 즐겨찾기