[Sping 핵심] 빈 팩 토리 와 팩 토리 빈.
24088 단어 Spring
빈 팩 토 리 는 가장 기본 적 인 IOC 용기 기능 을 제공 했다.이것 은 인터페이스 클래스 로 Default Listable BeanFactory, XmlBeanFactory, Application Context 등 은 용기 가 특정한 기능 을 부가 한 구체 적 인 실현 이 라 고 볼 수 있다.스프링 에 서 는 빈 을 빈 팩 토리 (즉 IOC 용기) 가 관리한다.
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
T getBean(String name, Class requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
T getBean(Class requiredType) throws BeansException;
T getBean(Class requiredType, Object... args) throws BeansException;
ObjectProvider getBeanProvider(Class requiredType);
ObjectProvider getBeanProvider(ResolvableType requiredType);
/**
* Bean
*/
boolean containsBean(String name);
/**
* Bean Singleton Bean
*/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
/**
* Bean Prototype Bean
*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
/**
* Bean Class Class
*/
boolean isTypeMatch(String name, Class> typeToMatch) throws NoSuchBeanDefinitionException;
/**
* Bean Class
*/
@Nullable
Class> getType(String name) throws NoSuchBeanDefinitionException;
/**
* Bean
*/
String[] getAliases(String name);
}
둘째, Factory Bean 이 무엇 입 니까?
Spring 에는 두 가지 유형의 Bean 이 있 는데 하 나 는 일반 Bean 이 고 다른 하 나 는 공장 Bean 즉 Factory Bean 이다.Factory Bean 은 일반 Bean 과 달리 돌아 오 는 대상 은 지정 한 클래스 의 인 스 턴 스 가 아니 라 이 Factory Bean 의 getObject 방법 으로 돌아 오 는 대상 입 니 다.만 든 대상 이 단일 사례 에 속 하 는 지 여 부 는 isSingleton 의 반환 에 의 해 결정 된다.
public interface FactoryBean {
/**
* FactoryBean“ ”
*/
@Nullable
T getObject() throws Exception;
/**
* getObject()
*/
@Nullable
Class> getObjectType();
/**
* “ ” singleton( ) 。 singleton , true, false
*/
//5.0
default boolean isSingleton() {
return true;
}
//5.0
boolean isSingleton();
}
3. 코드 인 스 턴 스
public interface FactoryBeanService {
/**
* FactoryBean
*/
public void testFactoryBean();
}
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
@Component
public class FactoryBeanStudy implements FactoryBean {
@Override
public FactoryBeanService getObject() throws Exception {
return new FactoryBeanServiceImpl();
}
@Override
public Class> getObjectType() {
return FactoryBeanService.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
import org.junit.Test;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class FactoryBeanServiceImpl implements FactoryBeanService {
@Override
public void testFactoryBean() {
System.out.println("test FactoryBean");
}
@Test
public void test() {
try {
ApplicationContext ctx = new ClassPathXmlApplicationContext("test.xml");
FactoryBeanService beanService = ctx.getBean(FactoryBeanService.class);
beanService.testFactoryBean();
System.out.println(beanService);
}catch (Exception e){
e.printStackTrace();
}
}
}
:
test FactoryBean
com.nuc.zp.sourcecode.ioc2.FactoryBeanServiceImpl@74bf1791
4. 소스 코드 분석
AbstractApplicationContext.class
@Override
public Map getBeansOfType(@Nullable Class type) throws BeansException {
// BeanFactory
assertBeanFactoryActive();
//getBeanFactory() DefaultListableBeanFactory
// DefaultListableBeanFactory getBean
return getBeanFactory().getBeansOfType(type);
}
DefaultListableBeanFactory.class
/**
* requiredType: com.nuc.zp.sourcecode.ioc2.FactoryBeanService
*/
@Override
public T getBean(Class requiredType) throws BeansException {
return getBean(requiredType, (Object[]) null);
}
@SuppressWarnings("unchecked")
@Override
public T getBean(Class requiredType, @Nullable Object... args) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
// bean
Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
if (resolved == null) {
throw new NoSuchBeanDefinitionException(requiredType);
}
return (T) resolved;
}
@Nullable
private T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
// NamedBeanHolder, requiredType 。
NamedBeanHolder namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
if (namedBean != null) {
return namedBean.getBeanInstance();
}
// Spring Bean ,
//SpringMVC
BeanFactory parent = getParentBeanFactory();
if (parent instanceof DefaultListableBeanFactory) {
return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
}
else if (parent != null) {
// , BeanFactory
ObjectProvider parentProvider = parent.getBeanProvider(requiredType);
if (args != null) {
return parentProvider.getObject(args);
}
else {
return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
}
}
return null;
}
/**
* NamedBeanHolder MapM
* beanName key factoryBeanStudy
* beanInstance value factoryBeanService
*/
public class NamedBeanHolder implements NamedBean {
private final String beanName;
private final T beanInstance;
/**
* Create a new holder for the given bean name plus instance.
* @param beanName the name of the bean
* @param beanInstance the corresponding bean instance
*/
public NamedBeanHolder(String beanName, T beanInstance) {
Assert.notNull(beanName, "Bean name must not be null");
this.beanName = beanName;
this.beanInstance = beanInstance;
}
/**
* Return the name of the bean.
*/
@Override
public String getBeanName() {
return this.beanName;
}
/**
* Return the corresponding bean instance.
*/
public T getBeanInstance() {
return this.beanInstance;
}
}
/**
* Bean
*/
@SuppressWarnings("unchecked")
@Nullable
private NamedBeanHolder resolveNamedBean(
ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
// Class BeanName, ( ),
// String 。 。
// , getBean type com.nuc.zp.sourcecode.ioc2.FactoryBeanService , Spring FactoryBeanService Bean
// beanName 。 ? getBeanNamesForType
String[] candidateNames = getBeanNamesForType(requiredType);
// BeanName, BeanName
if (candidateNames.length > 1) {
List autowireCandidates = new ArrayList<>(candidateNames.length);
for (String beanName : candidateNames) {
if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
autowireCandidates.add(beanName);
}
}
if (!autowireCandidates.isEmpty()) {
candidateNames = StringUtils.toStringArray(autowireCandidates);
}
}
// BeanName getBean Bean NamedBeanHolder
// bean beanName,beanType args bean
if (candidateNames.length == 1) {
String beanName = candidateNames[0];//factoryBeanStudy
// getBean , FactoryBean getObjectType , factoryBeanService
return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
}
// BeanName
else if (candidateNames.length > 1) {
Map candidates = new LinkedHashMap<>(candidateNames.length);
for (String beanName : candidateNames) {
// Bean
if (containsSingleton(beanName) && args == null) {
Object beanInstance = getBean(beanName);
candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
}
else {
// getType Bean
candidates.put(beanName, getType(beanName));
}
}
// Bean Primary Primary Bean
String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
if (candidateName == null) {
candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
}
if (candidateName != null) {
Object beanInstance = candidates.get(candidateName);
//Class getBean Bean
if (beanInstance == null || beanInstance instanceof Class) {
beanInstance = getBean(candidateName, requiredType.toClass(), args);
}
return new NamedBeanHolder<>(candidateName, (T) beanInstance);
}
if (!nonUniqueAsNull) {
//
throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
}
}
@Override
public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
Class> resolved = type.resolve();
if (resolved != null && !type.hasGenerics()) {
return getBeanNamesForType(resolved, includeNonSingletons, includeNonSingletons);
}
else {
return doGetBeanNamesForType(type, includeNonSingletons, includeNonSingletons);
}
}
@Override
public String[] getBeanNamesForType(@Nullable Class> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
//
Map, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
// doGetBeanNamesForType beanName
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
//
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
// ,
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List result = new ArrayList<>();
// beanName Spring Bean List
// Check all bean definitions.
for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name
// is not defined as alias for some other bean.
if (!isAlias(beanName)) {
try {
// beanName RootBeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
//RootBeanDefinition Bean 、
if (!mbd.isAbstract() && (allowEagerInit ||
(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
// FactoryBean
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
// isTypeMatch
// isTypeMatch true , beanName factoryBeanStudy result
boolean matchFound = false;
boolean allowFactoryBeanInit = allowEagerInit || containsSingleton(beanName);
boolean isNonLazyDecorated = dbd != null && !mbd.isLazyInit();
if (!isFactoryBean) {
// , FactoryBean beanName &beanName
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
//
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
else {
if (includeNonSingletons || isNonLazyDecorated ||
(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
if (!matchFound) {
// In case of FactoryBean, try to match FactoryBean instance itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
if (matchFound) {
result.add(beanName);
}
}
}
catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) {
if (allowEagerInit) {
throw ex;
}
// Probably a placeholder: let's ignore it for type matching purposes.
LogMessage message = (ex instanceof CannotLoadBeanClassException) ?
LogMessage.format("Ignoring bean class loading failure for bean '%s'", beanName) :
LogMessage.format("Ignoring unresolvable metadata in bean definition '%s'", beanName);
logger.trace(message, ex);
onSuppressedException(ex);
}
}
}
// Bean Spring Bean Environment
// Check manually registered singletons too.
for (String beanName : this.manualSingletonNames) {
try {
// In case of FactoryBean, match object created by FactoryBean.
if (isFactoryBean(beanName)) {
if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
result.add(beanName);
// Match found for this bean: do not match FactoryBean itself anymore.
continue;
}
// In case of FactoryBean, try to match FactoryBean itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
}
// Match raw bean instance (might be raw FactoryBean).
if (isTypeMatch(beanName, type)) {
result.add(beanName);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Shouldn't happen - probably a result of circular reference resolution...
logger.trace(LogMessage.format("Failed to check manually registered singleton with name '%s'", beanName), ex);
}
}
return StringUtils.toStringArray(result);
}
boolean isTypeMatch(String name, ResolvableType typeToMatch,
boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException {
// beanName beanName factoryBeanStudy Spring Bean
String beanName = transformedBeanName(name);
boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);
// AbstractApplicationContext Spring Bean
// beanName factoryBeanStudy Bean Bean
// : AbstractApplicationContext Spring Bean
// BeanFactory Bean ?
// Check manually registered singletons.
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
//factoryBeanStudy FactoryBean
if (beanInstance instanceof FactoryBean) {
// beanName & & Bean
if (!isFactoryDereference) {
// factoryBeanStudy type
Class> type = getTypeForFactoryBean((FactoryBean>) beanInstance);
// factoryBeanLearn type
return (type != null && typeToMatch.isAssignableFrom(type));
}
else {
return typeToMatch.isInstance(beanInstance);
}
}
else if (!isFactoryDereference) {
if (typeToMatch.isInstance(beanInstance)) {
// Direct match for exposed instance?
return true;
}
else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) {
// Generics potentially only match on the target class, not on the proxy...
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
Class> targetType = mbd.getTargetType();
if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance)) {
// Check raw class match as well, making sure it's exposed on the proxy.
Class> classToMatch = typeToMatch.resolve();
if (classToMatch != null && !classToMatch.isInstance(beanInstance)) {
return false;
}
if (typeToMatch.isAssignableFrom(targetType)) {
return true;
}
}
ResolvableType resolvableType = mbd.targetType;
if (resolvableType == null) {
resolvableType = mbd.factoryMethodReturnType;
}
return (resolvableType != null && typeToMatch.isAssignableFrom(resolvableType));
}
}
return false;
}
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
// null instance registered
return false;
}
// No singleton instance found -> check bean definition.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// No bean definition found in this factory -> delegate to parent.
return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
}
// Retrieve corresponding bean definition.
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
// Setup the types that we want to match against
Class> classToMatch = typeToMatch.resolve();
if (classToMatch == null) {
classToMatch = FactoryBean.class;
}
Class>[] typesToMatch = (FactoryBean.class == classToMatch ?
new Class>[] {classToMatch} : new Class>[] {FactoryBean.class, classToMatch});
// Attempt to predict the bean type
Class> predictedType = null;
// We're looking for a regular reference but we're a factory bean that has
// a decorated bean definition. The target bean should be the same type
// as FactoryBean would ultimately return.
if (!isFactoryDereference && dbd != null && isFactoryBean(beanName, mbd)) {
// We should only attempt if the user explicitly set lazy-init to true
// and we know the merged bean definition is for a factory bean.
if (!mbd.isLazyInit() || allowFactoryBeanInit) {
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
Class> targetType = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
if (targetType != null && !FactoryBean.class.isAssignableFrom(targetType)) {
predictedType = targetType;
}
}
}
// If we couldn't use the target type, try regular prediction.
if (predictedType == null) {
predictedType = predictBeanType(beanName, mbd, typesToMatch);
if (predictedType == null) {
return false;
}
}
// Attempt to get the actual ResolvableType for the bean.
ResolvableType beanType = null;
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
if (FactoryBean.class.isAssignableFrom(predictedType)) {
if (beanInstance == null && !isFactoryDereference) {
beanType = getTypeForFactoryBean(beanName, mbd, allowFactoryBeanInit);
predictedType = beanType.resolve();
if (predictedType == null) {
return false;
}
}
}
else if (isFactoryDereference) {
// Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
// type but we nevertheless are being asked to dereference a FactoryBean...
// Let's check the original bean class and proceed with it if it is a FactoryBean.
predictedType = predictBeanType(beanName, mbd, FactoryBean.class);
if (predictedType == null || !FactoryBean.class.isAssignableFrom(predictedType)) {
return false;
}
}
// We don't have an exact type but if bean definition target type or the factory
// method return type matches the predicted type then we can use that.
if (beanType == null) {
ResolvableType definedType = mbd.targetType;
if (definedType == null) {
definedType = mbd.factoryMethodReturnType;
}
if (definedType != null && definedType.resolve() == predictedType) {
beanType = definedType;
}
}
// If we have a bean type use it so that generics are considered
if (beanType != null) {
return typeToMatch.isAssignableFrom(beanType);
}
// If we don't have a bean type, fallback to the predicted type
return typeToMatch.isAssignableFrom(predictedType);
}
위의 분석 은 다음 과 같다. 우리 가 getBean (Class required Type) 방법 을 사용 하여 용기 에 있 는 bean 을 유형 에 따라 가 져 올 때 대응 하 는 예 는 유형 Factory Bean Service 에 따라 Spring 용기 에서 Bean 을 가 져 오 는 것 이다.(우선 명확 한 것 은 Spring 용기 에 Factory BeanService 타 입의 BeanDefinition 이 없다 는 것 이다. 그러나 하나의 Bean 은 Factory BeanService 타 입 과 관련 이 있다.). Spring 은 type 에 따라 Bean 을 가 져 올 때 beanName 을 가 져 옵 니 다. beanName 을 가 져 오 는 과정 은 다음 과 같 습 니 다. Spring 용기 에 있 는 모든 beanName 을 순환 한 다음 beanName 에 따라 해당 하 는 BeanDefinition 을 가 져 옵 니 다. 현재 bean 이 Factory Bean 형식 이 라면 Spring 용기 에서 BeanName 에 따라 해당 하 는 Bean 인 스 턴 스 를 가 져 오고 가 져 온 Bean 인 스 턴 스 의 get 을 호출 합 니 다.Object Type 방법 은 Class 형식 을 가 져 옵 니 다. 이 Class 유형 이 우리 가 들 어 오 는 Class 와 같은 유형 인지 판단 합 니 다. 만약 그렇다면 beanName 을 되 돌려 주 십시오. 이에 대응 하 는 것 은 factory BeanStudy 에 따라 Factory BeanStudy 인 스 턴 스 를 가 져 옵 니 다. Factory BeanStudy 의 getObject Type 방법 으로 반환 값 Factory Bean Service. class 를 가 져 옵 니 다. 우리 가 들 어 오 는 유형 과 일치 합 니 다.여기 서 얻 은 beanName 을 factory BeanStudy 로 합 니 다. 다시 말 하면 factory BeanStudy 라 는 beanName 을 factory BeanService 유형 으로 표시 합 니 다. 즉, Factory BeanService 유형 에 대응 하 는 beanName 을 factory BeanStudy 로 표시 하 는 것 이 중요 합 니 다.
총화
BeanFactory 에 서 는 Spring 용기 에 있 는 Bean 을 만 들 고 관리 할 수 있 습 니 다. Bean 을 만 드 는 데 통 일 된 절차 가 있 습 니 다. Factory Bean 은 공장 Bean 으로 특정한 유형의 Bean 인 스 턴 스 를 생 성 할 수 있 습 니 다. 가장 큰 역할 은 Bean 의 생 성 과정 을 사용자 정의 할 수 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[MeU] Hashtag 기능 개발➡️ 기존 Tag 테이블에 존재하지 않는 해시태그라면 Tag , tagPostMapping 테이블에 모두 추가 ➡️ 기존에 존재하는 해시태그라면, tagPostMapping 테이블에만 추가 이후에 개발할 태그 기반 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.