spring-ioc
Spring IOC
那么。什么是IOC呢?IOC是Inversion of Control的缩写,是一个很重要的面向对象法则。主要目的是用来消减计算机程序的耦合问题。相同也是Spring框架的核心。
IOC一般分为两种类型,依赖注入(Dependency Injection)和依赖查找(Dependency Lookup),在Spring Framework框架中主要是依赖注入。
作为spring的核心,那IOC究竟是什么呢?
public class User{ private String id; private String name; private String password; private Date birthday; //ignore other properties... //ignore setter getter method } public interface IUserDao{ public void add(User user); public void delete(User user); public List<User> findAll(); } public class UserDaoImpl{ public void add(User user){ //ignore the implementation } public void delete(User user){ //ignore the implementation } public List<User> findAll(){ //ignore the implementation } } public class UserController{ private IUserDao userDao = new UserDaoImpl(); @RequestMapping("/user/add") public void add(User user){ userDao.add(user); } @RequestMapping("/user/delete") public void delete(User user){ userDao.add(user); } @RequestMapping("/user/findAll") public void findAll(User user){ List<User> allUser = userDao.findAll(); } }在这里面,UserController调用private IUserDao userDao = new UserDaoImpl()来初始化userDao。因为java是一门编译语言,也就是将.java变成.class的过程。在这个过程中捆绑了IUserDao的实现,也就是UserDaoImpl。尽管开发人员使用了面向接口编程的风格来书写代码,可是还是和UserDaoImpl捆绑在了一起。假设后期开发中,为IUserDao提供第二种实现,比方:将orm框架由mybatis换成了hibernate。那么就须要改动源代码UserController的实现。
传统模式中,一个类依赖的其它类都由自己维护。须要什么类,就new一个。
这样的开发方式的耦合性比較高,不利于后期的维护。那么既然这样的方式不好。那么有没有一种其它办法来解决问题呢?没错,IOC能够很好的解决问题。
IOC组成
public class User{ private String id; private String name; private String password; private Date birthday; //ignore other properties... //ignore setter getter method<span style="white-space:pre"> </span> } public interface IUserDao{ public void add(User user); public void delete(User user); public List<User> findAll(); } @Repository public class UserDaoImpl{ public void add(User user){ //ignore the implementation } public void delete(User user){ //ignore the implementation } public List<User> findAll(){ //ignore the implementation } } @Controller public class UserController{ //主动注入这个类 @Autowired private IUserDao userDao userDao; @RequestMapping("/user/add") public void add(User user){ userDao.add(user); } @RequestMapping("/user/delete") public void delete(User user){ userDao.add(user); } @RequestMapping("/user/findAll") public void findAll(User user){ List<User> allUser = userDao.findAll(); } }从代码中我们能够看到,这两份代码差点儿是一样的,就仅仅是去掉了userDao的实现类,在userDao变量中增加了@Autowired注解而已。没错。这就是spring的厉害之处,由于spring是一种无侵入式的轻量级框架。那么spring是怎样实现控制反转的呢?以下先给出一个spring ioc图
IOC的实现
当然,这个图不过一个思维导图,详细代码的细节。肯定得复杂的多。以下给出一个spring默认的实现类,不必要的信息做了删除
/** * * 一个BeanFactory的实现类,不必要的信息作了删除,有兴趣的读者能够查看源代码 * */ @SuppressWarnings("serial") public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { private static Class<?> javaxInjectProviderClass = null; static { ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader(); try { javaxInjectProviderClass = cl.loadClass("javax.inject.Provider"); } catch (ClassNotFoundException ex) { // JSR-330 API not available - Provider interface simply not supported then. } } /** Map from serialized id to factory instance */ private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories = new ConcurrentHashMap<String, Reference<DefaultListableBeanFactory>>(8); /** Optional id for this factory, for serialization purposes */ private String serializationId; /** Whether to allow re-registration of a different definition with the same name */ private boolean allowBeanDefinitionOverriding = true; /** Whether to allow eager class loading even for lazy-init beans */ private boolean allowEagerClassLoading = true; /** Resolver to use for checking if a bean definition is an autowire candidate */ private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver(); /** 用于缓存解决好依赖关系的bean */ private final Map<Class<?>, Object> resolvableDependencies = new HashMap<Class<?>, Object>(16); /** 保存源信息 */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64); /** Map of singleton and non-singleton bean names keyed by dependency type */ private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64); /** Map of singleton-only bean names keyed by dependency type */ private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?
>, String[]>(64); /***/ private final List<String> beanDefinitionNames = new ArrayList<String>(); /** Whether bean definition metadata may be cached for all beans */ private boolean configurationFrozen = false; /** Cached array of bean definition names in case of frozen configuration */ private String[] frozenBeanDefinitionNames; /** * Create a new DefaultListableBeanFactory. */ public DefaultListableBeanFactory() { super(); } /** * Create a new DefaultListableBeanFactory with the given parent. * @param parentBeanFactory the parent BeanFactory */ public DefaultListableBeanFactory(BeanFactory parentBeanFactory) { super(parentBeanFactory); } /** * Specify an id for serialization purposes, allowing this BeanFactory to be * deserialized from this id back into the BeanFactory object, if needed. */ public void setSerializationId(String serializationId) { if (serializationId != null) { serializableFactories.put(serializationId, new WeakReference<DefaultListableBeanFactory>(this)); } else if (this.serializationId != null) { serializableFactories.remove(this.serializationId); } this.serializationId = serializationId; } /** * Set whether it should be allowed to override bean definitions by registering * a different definition with the same name, automatically replacing the former. * If not, an exception will be thrown. This also applies to overriding aliases. * <p>Default is "true". * @see #registerBeanDefinition */ public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) { this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding; } /** * Set whether the factory is allowed to eagerly load bean classes * even for bean definitions that are marked as "lazy-init". * <p>Default is "true". Turn this flag off to suppress class loading * for lazy-init beans unless such a bean is explicitly requested. * In particular, by-type lookups will then simply ignore bean definitions * without resolved class name, instead of loading the bean classes on * demand just to perform a type check. * @see AbstractBeanDefinition#setLazyInit */ public void setAllowEagerClassLoading(boolean allowEagerClassLoading) { this.allowEagerClassLoading = allowEagerClassLoading; } /** * Set a custom autowire candidate resolver for this BeanFactory to use * when deciding whether a bean definition should be considered as a * candidate for autowiring. */ public void setAutowireCandidateResolver(final AutowireCandidateResolver autowireCandidateResolver) { Assert.notNull(autowireCandidateResolver, "AutowireCandidateResolver must not be null"); if (autowireCandidateResolver instanceof BeanFactoryAware) { if (System.getSecurityManager() != null) { final BeanFactory target = this; AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { ((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(target); return null; } }, getAccessControlContext()); } else { ((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(this); } } this.autowireCandidateResolver = autowireCandidateResolver; } /** * Return the autowire candidate resolver for this BeanFactory (never {@code null}). */ public AutowireCandidateResolver getAutowireCandidateResolver() { return this.autowireCandidateResolver; } @Override public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) { super.copyConfigurationFrom(otherFactory); if (otherFactory instanceof DefaultListableBeanFactory) { DefaultListableBeanFactory otherListableFactory = (DefaultListableBeanFactory) otherFactory; this.allowBeanDefinitionOverriding = otherListableFactory.allowBeanDefinitionOverriding; this.allowEagerClassLoading = otherListableFactory.allowEagerClassLoading; this.autowireCandidateResolver = otherListableFactory.autowireCandidateResolver; this.resolvableDependencies.putAll(otherListableFactory.resolvableDependencies); } } //--------------------------------------------------------------------- // Implementation of ListableBeanFactory interface //--------------------------------------------------------------------- public <T> T getBean(Class<T> requiredType) throws BeansException { Assert.notNull(requiredType, "Required type must not be null"); String[] beanNames = getBeanNamesForType(requiredType); if (beanNames.length > 1) { ArrayList<String> autowireCandidates = new ArrayList<String>(); for (String beanName : beanNames) { if (getBeanDefinition(beanName).isAutowireCandidate()) { autowireCandidates.add(beanName); } } if (autowireCandidates.size() > 0) { beanNames = autowireCandidates.toArray(new String[autowireCandidates.size()]); } } if (beanNames.length == 1) { return getBean(beanNames[0], requiredType); } else if (beanNames.length > 1) { T primaryBean = null; for (String beanName : beanNames) { T beanInstance = getBean(beanName, requiredType); if (isPrimary(beanName, beanInstance)) { if (primaryBean != null) { throw new NoUniqueBeanDefinitionException(requiredType, beanNames.length, "more than one 'primary' bean found of required type: " + Arrays.asList(beanNames)); } primaryBean = beanInstance; } } if (primaryBean != null) { return primaryBean; } throw new NoUniqueBeanDefinitionException(requiredType, beanNames); } else if (getParentBeanFactory() != null) { return getParentBeanFactory().getBean(requiredType); } else { throw new NoSuchBeanDefinitionException(requiredType); } } @Override public boolean containsBeanDefinition(String beanName) { Assert.notNull(beanName, "Bean name must not be null"); return this.beanDefinitionMap.containsKey(beanName); } public int getBeanDefinitionCount() { return this.beanDefinitionMap.size(); } public String[] getBeanDefinitionNames() { synchronized (this.beanDefinitionMap) { if (this.frozenBeanDefinitionNames != null) { return this.frozenBeanDefinitionNames; } else { return StringUtils.toStringArray(this.beanDefinitionNames); } } } public String[] getBeanNamesForType(Class<?
> type) { return getBeanNamesForType(type, true, true); } public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) { if (!isConfigurationFrozen() || type == null || !allowEagerInit) { return doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit); } Map<Class<?>, String[]> cache = (includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType); String[] resolvedBeanNames = cache.get(type); if (resolvedBeanNames != null) { return resolvedBeanNames; } resolvedBeanNames = doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit); cache.put(type, resolvedBeanNames); return resolvedBeanNames; } private String[] doGetBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) { List<String> result = new ArrayList<String>(); // Check all bean definitions. String[] beanDefinitionNames = getBeanDefinitionNames(); for (String beanName : beanDefinitionNames) { // Only consider bean as eligible if the bean name // is not defined as alias for some other bean. if (!isAlias(beanName)) { try { RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // Only check bean definition if it is complete. if (!mbd.isAbstract() && (allowEagerInit || ((mbd.hasBeanClass() || !mbd.isLazyInit() || this.allowEagerClassLoading)) && !requiresEagerInitForType(mbd.getFactoryBeanName()))) { // In case of FactoryBean, match object created by FactoryBean. boolean isFactoryBean = isFactoryBean(beanName, mbd); boolean matchFound = (allowEagerInit || !isFactoryBean || containsSingleton(beanName)) && (includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type); if (!matchFound && isFactoryBean) { // In case of FactoryBean, try to match FactoryBean instance itself next. beanName = FACTORY_BEAN_PREFIX + beanName; matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type); } if (matchFound) { result.add(beanName); } } } catch (CannotLoadBeanClassException ex) { if (allowEagerInit) { throw ex; } // Probably contains a placeholder: let's ignore it for type matching purposes. if (this.logger.isDebugEnabled()) { this.logger.debug("Ignoring bean class loading failure for bean '" + beanName + "'", ex); } onSuppressedException(ex); } catch (BeanDefinitionStoreException ex) { if (allowEagerInit) { throw ex; } // Probably contains a placeholder: let's ignore it for type matching purposes. if (this.logger.isDebugEnabled()) { this.logger.debug("Ignoring unresolvable metadata in bean definition '" + beanName + "'", ex); } onSuppressedException(ex); } } } // Check singletons too, to catch manually registered singletons. String[] singletonNames = getSingletonNames(); for (String beanName : singletonNames) { // Only check if manually registered. if (!containsBeanDefinition(beanName)) { // 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); } } } return StringUtils.toStringArray(result); } /** * Check whether the specified bean would need to be eagerly initialized * in order to determine its type. * @param factoryBeanName a factory-bean reference that the bean definition * defines a factory method for * @return whether eager initialization is necessary */ private boolean requiresEagerInitForType(String factoryBeanName) { return (factoryBeanName != null && isFactoryBean(factoryBeanName) && !containsSingleton(factoryBeanName)); } public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException { return getBeansOfType(type, true, true); } public <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException { String[] beanNames = getBeanNamesForType(type, includeNonSingletons, allowEagerInit); Map<String, T> result = new LinkedHashMap<String, T>(beanNames.length); for (String beanName : beanNames) { try { result.put(beanName, getBean(beanName, type)); } catch (BeanCreationException ex) { Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; if (isCurrentlyInCreation(bce.getBeanName())) { if (this.logger.isDebugEnabled()) { this.logger.debug("Ignoring match to currently created bean '" + beanName + "': " + ex.getMessage()); } onSuppressedException(ex); // Ignore: indicates a circular reference when autowiring constructors. // We want to find matches other than the currently created bean itself. continue; } } throw ex; } } return result; } public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) { Set<String> beanNames = new LinkedHashSet<String>(getBeanDefinitionCount()); beanNames.addAll(Arrays.asList(getBeanDefinitionNames())); beanNames.addAll(Arrays.asList(getSingletonNames())); Map<String, Object> results = new LinkedHashMap<String, Object>(); for (String beanName : beanNames) { if (findAnnotationOnBean(beanName, annotationType) != null) { results.put(beanName, getBean(beanName)); } } return results; } /** * Find a {@link Annotation} of {@code annotationType} on the specified * bean, traversing its interfaces and super classes if no annotation can be * found on the given class itself, as well as checking its raw bean class * if not found on the exposed bean reference (e.g. in case of a proxy). */ public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) { A ann = null; Class<?
> beanType = getType(beanName); if (beanType != null) { ann = AnnotationUtils.findAnnotation(beanType, annotationType); } if (ann == null && containsBeanDefinition(beanName)) { BeanDefinition bd = getMergedBeanDefinition(beanName); if (bd instanceof AbstractBeanDefinition) { AbstractBeanDefinition abd = (AbstractBeanDefinition) bd; if (abd.hasBeanClass()) { ann = AnnotationUtils.findAnnotation(abd.getBeanClass(), annotationType); } } } return ann; } //--------------------------------------------------------------------- // Implementation of ConfigurableListableBeanFactory interface //--------------------------------------------------------------------- public void registerResolvableDependency(Class<?> dependencyType, Object autowiredValue) { Assert.notNull(dependencyType, "Type must not be null"); if (autowiredValue != null) { Assert.isTrue((autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue)), "Value [" + autowiredValue + "] does not implement specified type [" + dependencyType.getName() + "]"); this.resolvableDependencies.put(dependencyType, autowiredValue); } } public boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor) throws NoSuchBeanDefinitionException { // Consider FactoryBeans as autowiring candidates. boolean isFactoryBean = (descriptor != null && descriptor.getDependencyType() != null && FactoryBean.class.isAssignableFrom(descriptor.getDependencyType())); if (isFactoryBean) { beanName = BeanFactoryUtils.transformedBeanName(beanName); } if (containsBeanDefinition(beanName)) { return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(beanName), descriptor); } else if (containsSingleton(beanName)) { return isAutowireCandidate(beanName, new RootBeanDefinition(getType(beanName)), descriptor); } else if (getParentBeanFactory() instanceof ConfigurableListableBeanFactory) { // No bean definition found in this factory -> delegate to parent. return ((ConfigurableListableBeanFactory) getParentBeanFactory()).isAutowireCandidate(beanName, descriptor); } else { return true; } } /** * Determine whether the specified bean definition qualifies as an autowire candidate, * to be injected into other beans which declare a dependency of matching type. * @param beanName the name of the bean definition to check * @param mbd the merged bean definition to check * @param descriptor the descriptor of the dependency to resolve * @return whether the bean should be considered as autowire candidate */ protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd, DependencyDescriptor descriptor) { resolveBeanClass(mbd, beanName); if (mbd.isFactoryMethodUnique) { boolean resolve; synchronized (mbd.constructorArgumentLock) { resolve = (mbd.resolvedConstructorOrFactoryMethod == null); } if (resolve) { new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd); } } return getAutowireCandidateResolver().isAutowireCandidate( new BeanDefinitionHolder(mbd, beanName, getAliases(beanName)), descriptor); } @Override public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { BeanDefinition bd = this.beanDefinitionMap.get(beanName); if (bd == null) { if (this.logger.isTraceEnabled()) { this.logger.trace("No bean named '" + beanName + "' found in " + this); } throw new NoSuchBeanDefinitionException(beanName); } return bd; } public void freezeConfiguration() { this.configurationFrozen = true; synchronized (this.beanDefinitionMap) { this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames); } } public boolean isConfigurationFrozen() { return this.configurationFrozen; } /** * Considers all beans as eligible for metadata caching * if the factory's configuration has been marked as frozen. * @see #freezeConfiguration() */ @Override protected boolean isBeanEligibleForMetadataCaching(String beanName) { return (this.configurationFrozen || super.isBeanEligibleForMetadataCaching(beanName)); } public void preInstantiateSingletons() throws BeansException { if (this.logger.isInfoEnabled()) { this.logger.info("Pre-instantiating singletons in " + this); } List<String> beanNames; synchronized (this.beanDefinitionMap) { // Iterate over a copy to allow for init methods which in turn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. beanNames = new ArrayList<String>(this.beanDefinitionNames); } for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { final FactoryBean<?
> factory = (FactoryBean<?
>) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { public Boolean run() { return ((SmartFactoryBean<?>) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?
>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } else { getBean(beanName); } } } } //--------------------------------------------------------------------- // Implementation of BeanDefinitionRegistry interface //--------------------------------------------------------------------- public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } synchronized (this.beanDefinitionMap) { Object oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!this.allowBeanDefinitionOverriding) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } } else { this.beanDefinitionNames.add(beanName); this.frozenBeanDefinitionNames = null; } this.beanDefinitionMap.put(beanName, beanDefinition); } resetBeanDefinition(beanName); } public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { Assert.hasText(beanName, "'beanName' must not be empty"); synchronized (this.beanDefinitionMap) { BeanDefinition bd = this.beanDefinitionMap.remove(beanName); if (bd == null) { if (this.logger.isTraceEnabled()) { this.logger.trace("No bean named '" + beanName + "' found in " + this); } throw new NoSuchBeanDefinitionException(beanName); } this.beanDefinitionNames.remove(beanName); this.frozenBeanDefinitionNames = null; } resetBeanDefinition(beanName); } /** * Reset all bean definition caches for the given bean, * including the caches of beans that are derived from it. * @param beanName the name of the bean to reset */ protected void resetBeanDefinition(String beanName) { // Remove the merged bean definition for the given bean, if already created. clearMergedBeanDefinition(beanName); // Remove corresponding bean from singleton cache, if any. Shouldn't usually // be necessary, rather just meant for overriding a context's default beans // (e.g. the default StaticMessageSource in a StaticApplicationContext). destroySingleton(beanName); // Remove any assumptions about by-type mappings. clearByTypeCache(); // Reset all bean definitions that have the given bean as parent (recursively). for (String bdName : this.beanDefinitionNames) { if (!beanName.equals(bdName)) { BeanDefinition bd = this.beanDefinitionMap.get(bdName); if (beanName.equals(bd.getParentName())) { resetBeanDefinition(bdName); } } } } /** * Only allows alias overriding if bean definition overriding is allowed. */ @Override protected boolean allowAliasOverriding() { return this.allowBeanDefinitionOverriding; } @Override public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException { super.registerSingleton(beanName, singletonObject); clearByTypeCache(); } @Override public void destroySingleton(String beanName) { super.destroySingleton(beanName); clearByTypeCache(); } /** * Remove any assumptions about by-type mappings. */ private void clearByTypeCache() { this.allBeanNamesByType.clear(); this.singletonBeanNamesByType.clear(); } //--------------------------------------------------------------------- // Dependency resolution functionality //--------------------------------------------------------------------- public Object resolveDependency(DependencyDescriptor descriptor, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException { descriptor.initParameterNameDiscovery(getParameterNameDiscoverer()); if (descriptor.getDependencyType().equals(ObjectFactory.class)) { return new DependencyObjectFactory(descriptor, beanName); } else if (descriptor.getDependencyType().equals(javaxInjectProviderClass)) { return new DependencyProviderFactory().createDependencyProvider(descriptor, beanName); } else { return doResolveDependency(descriptor, descriptor.getDependencyType(), beanName, autowiredBeanNames, typeConverter); } } protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException { Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); if (value != null) { if (value instanceof String) { String strVal = resolveEmbeddedValue((String) value); BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); value = evaluateBeanDefinitionString(strVal, bd); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); return (descriptor.getField() != null ? converter.convertIfNecessary(value, type, descriptor.getField()) : converter.convertIfNecessary(value, type, descriptor.getMethodParameter())); } if (type.isArray()) { Class<?
> componentType = type.getComponentType(); Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, descriptor); if (matchingBeans.isEmpty()) { if (descriptor.isRequired()) { raiseNoSuchBeanDefinitionException(componentType, "array of " + componentType.getName(), descriptor); } return null; } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); return converter.convertIfNecessary(matchingBeans.values(), type); } else if (Collection.class.isAssignableFrom(type) && type.isInterface()) { Class<?> elementType = descriptor.getCollectionType(); if (elementType == null) { if (descriptor.isRequired()) { throw new FatalBeanException("No element type declared for collection [" + type.getName() + "]"); } return null; } Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, descriptor); if (matchingBeans.isEmpty()) { if (descriptor.isRequired()) { raiseNoSuchBeanDefinitionException(elementType, "collection of " + elementType.getName(), descriptor); } return null; } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); return converter.convertIfNecessary(matchingBeans.values(), type); } else if (Map.class.isAssignableFrom(type) && type.isInterface()) { 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; } Class<?> valueType = descriptor.getMapValueType(); if (valueType == null) { if (descriptor.isRequired()) { throw new FatalBeanException("No value type declared for map [" + type.getName() + "]"); } return null; } Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor); if (matchingBeans.isEmpty()) { if (descriptor.isRequired()) { raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor); } return null; } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } return matchingBeans; } else { Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { if (descriptor.isRequired()) { raiseNoSuchBeanDefinitionException(type, "", descriptor); } return null; } if (matchingBeans.size() > 1) { String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor); if (primaryBeanName == null) { throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet()); } if (autowiredBeanNames != null) { autowiredBeanNames.add(primaryBeanName); } return matchingBeans.get(primaryBeanName); } // We have exactly one match. Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next(); if (autowiredBeanNames != null) { autowiredBeanNames.add(entry.getKey()); } return entry.getValue(); } } /** * Find bean instances that match the required type. * Called during autowiring for the specified bean. * @param beanName the name of the bean that is about to be wired * @param requiredType the actual type of bean to look for * (may be an array component type or collection element type) * @param descriptor the descriptor of the dependency to resolve * @return a Map of candidate names and candidate instances that match * the required type (never {@code null}) * @throws BeansException in case of errors * @see #autowireByType * @see #autowireConstructor */ protected Map<String, Object> findAutowireCandidates( String beanName, Class<?
> requiredType, DependencyDescriptor descriptor) { String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this, requiredType, true, descriptor.isEager()); Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length); for (Class<?> autowiringType : this.resolvableDependencies.keySet()) { if (autowiringType.isAssignableFrom(requiredType)) { Object autowiringValue = this.resolvableDependencies.get(autowiringType); autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType); if (requiredType.isInstance(autowiringValue)) { result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue); break; } } } for (String candidateName : candidateNames) { if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) { result.put(candidateName, getBean(candidateName)); } } return result; } /** * Determine the primary autowire candidate in the given set of beans. * @param candidateBeans a Map of candidate names and candidate instances * that match the required type, as returned by {@link #findAutowireCandidates} * @param descriptor the target dependency to match against * @return the name of the primary candidate, or {@code null} if none found */ protected String determinePrimaryCandidate(Map<String, Object> candidateBeans, DependencyDescriptor descriptor) { String primaryBeanName = null; String fallbackBeanName = null; for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) { String candidateBeanName = entry.getKey(); Object beanInstance = entry.getValue(); if (isPrimary(candidateBeanName, beanInstance)) { if (primaryBeanName != null) { boolean candidateLocal = containsBeanDefinition(candidateBeanName); boolean primaryLocal = containsBeanDefinition(primaryBeanName); if (candidateLocal == primaryLocal) { throw new NoUniqueBeanDefinitionException(descriptor.getDependencyType(), candidateBeans.size(), "more than one 'primary' bean found among candidates: " + candidateBeans.keySet()); } else if (candidateLocal && !primaryLocal) { primaryBeanName = candidateBeanName; } } else { primaryBeanName = candidateBeanName; } } if (primaryBeanName == null && (this.resolvableDependencies.values().contains(beanInstance) || matchesBeanName(candidateBeanName, descriptor.getDependencyName()))) { fallbackBeanName = candidateBeanName; } } return (primaryBeanName != null ?
primaryBeanName : fallbackBeanName); } /** * Return whether the bean definition for the given bean name has been * marked as a primary bean. * @param beanName the name of the bean * @param beanInstance the corresponding bean instance * @return whether the given bean qualifies as primary */ protected boolean isPrimary(String beanName, Object beanInstance) { if (containsBeanDefinition(beanName)) { return getMergedLocalBeanDefinition(beanName).isPrimary(); } BeanFactory parentFactory = getParentBeanFactory(); return (parentFactory instanceof DefaultListableBeanFactory && ((DefaultListableBeanFactory) parentFactory).isPrimary(beanName, beanInstance)); } /** * Determine whether the given candidate name matches the bean name or the aliases * stored in this bean definition. */ protected boolean matchesBeanName(String beanName, String candidateName) { return (candidateName != null && (candidateName.equals(beanName) || ObjectUtils.containsElement(getAliases(beanName), candidateName))); } /** * Raise a NoSuchBeanDefinitionException for an unresolvable dependency. */ private void raiseNoSuchBeanDefinitionException( Class<?> type, String dependencyDescription, DependencyDescriptor descriptor) throws NoSuchBeanDefinitionException { throw new NoSuchBeanDefinitionException(type, dependencyDescription, "expected at least 1 bean which qualifies as autowire candidate for this dependency. " + "Dependency annotations: " + ObjectUtils.nullSafeToString(descriptor.getAnnotations())); } @Override public String toString() { StringBuilder sb = new StringBuilder(ObjectUtils.identityToString(this)); sb.append(": defining beans ["); sb.append(StringUtils.arrayToCommaDelimitedString(getBeanDefinitionNames())); sb.append("]; "); BeanFactory parent = getParentBeanFactory(); if (parent == null) { sb.append("root of factory hierarchy"); } else { sb.append("parent: ").append(ObjectUtils.identityToString(parent)); } return sb.toString(); } //--------------------------------------------------------------------- // Serialization support //--------------------------------------------------------------------- private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { throw new NotSerializableException("DefaultListableBeanFactory itself is not deserializable - " + "just a SerializedBeanFactoryReference is"); } protected Object writeReplace() throws ObjectStreamException { if (this.serializationId != null) { return new SerializedBeanFactoryReference(this.serializationId); } else { throw new NotSerializableException("DefaultListableBeanFactory has no serialization id"); } } /** * Minimal id reference to the factory. * Resolved to the actual factory instance on deserialization. */ private static class SerializedBeanFactoryReference implements Serializable { private final String id; public SerializedBeanFactoryReference(String id) { this.id = id; } private Object readResolve() { Reference<?
> ref = serializableFactories.get(this.id); if (ref == null) { throw new IllegalStateException( "Cannot deserialize BeanFactory with id " + this.id + ": no factory registered for this id"); } Object result = ref.get(); if (result == null) { throw new IllegalStateException( "Cannot deserialize BeanFactory with id " + this.id + ": factory has been garbage-collected"); } return result; } } /** * Serializable ObjectFactory for lazy resolution of a dependency. */ private class DependencyObjectFactory implements ObjectFactory<Object>, Serializable { private final DependencyDescriptor descriptor; private final String beanName; public DependencyObjectFactory(DependencyDescriptor descriptor, String beanName) { this.descriptor = new DependencyDescriptor(descriptor); this.descriptor.increaseNestingLevel(); this.beanName = beanName; } public Object getObject() throws BeansException { return doResolveDependency(this.descriptor, this.descriptor.getDependencyType(), this.beanName, null, null); } } /** * Serializable ObjectFactory for lazy resolution of a dependency. */ private class DependencyProvider extends DependencyObjectFactory implements Provider<Object> { public DependencyProvider(DependencyDescriptor descriptor, String beanName) { super(descriptor, beanName); } public Object get() throws BeansException { return getObject(); } } /** * Separate inner class for avoiding a hard dependency on the {@code javax.inject} API. */ private class DependencyProviderFactory { public Object createDependencyProvider(DependencyDescriptor descriptor, String beanName) { return new DependencyProvider(descriptor, beanName); } } }
BeanFactory
在IOC模块中,大量使用了工厂设计模式来完毕类的初始化。
整个IOC中,最大的工厂接口便是BeanFactory。里面定义了了一些主要的方法去获取java bean,例如以下代码所看到的
package org.springframework.beans.factory; import org.springframework.beans.BeansException; /** * IOC中工厂类的基类,定义了一些列获取java bean对象的方法 */ public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; /**依据名字获取java bean对象 * @param name the name of the bean to retrieve * @return an instance of the bean * @throws NoSuchBeanDefinitionException if there is no bean definition * with the specified name * @throws BeansException if the bean could not be obtained */ Object getBean(String name) throws BeansException; /** * 依据名字获取指定类型的java bean对象 * @return an instance of the bean * @throws NoSuchBeanDefinitionException if there is no such bean definition * @throws BeanNotOfRequiredTypeException if the bean is not of the required type * @throws BeansException if the bean could not be created */ <T> T getBean(String name, Class<T> requiredType) throws BeansException; /** *依据类型获取指定类型的java bean对象,这里使用了泛型技术 * @return an instance of the single bean matching the required type * @throws NoSuchBeanDefinitionException if no bean of the given type was found * @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found * @since 3.0 * @see ListableBeanFactory */ <T> T getBean(Class<T> requiredType) throws BeansException; /** * Return an instance, which may be shared or independent, of the specified bean. * <p>Allows for specifying explicit constructor arguments / factory method arguments, * overriding the specified default arguments (if any) in the bean definition. * @param name the name of the bean to retrieve * @param args arguments to use if creating a prototype using explicit arguments to a * static factory method. It is invalid to use a non-null args value in any other case. * @return an instance of the bean * @throws NoSuchBeanDefinitionException if there is no such bean definition * @throws BeanDefinitionStoreException if arguments have been given but * the affected bean isn't a prototype * @throws BeansException if the bean could not be created * @since 2.5 */ Object getBean(String name, Object... args) throws BeansException; /** * 推断IOC容器中是否有指定名字的java bean对象 * @param name the name of the bean to query * @return whether a bean with the given name is present */ boolean containsBean(String name); /** * 推断指定名字的java bean对象是否为单例模式 * @see #getBean * @see #isPrototype */ boolean isSingleton(String name) throws NoSuchBeanDefinitionException; /** * 推断指定名字的java bean对象是否为原型设计模式 * @since 2.0.3 * @see #getBean * @see #isSingleton */ boolean isPrototype(String name) throws NoSuchBeanDefinitionException; /** * 推断指定名字的java bean对象是否为targetType的类型 * @since 2.0.1 * @see #getBean * @see #getType */ boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException; /** * 获取指定名字的java bean对象的类型 * @since 1.1.2 * @see #getBean * @see #isTypeMatch */ Class<?> getType(String name) throws NoSuchBeanDefinitionException; /**获取指定名字的java bean对象的别名,一个对象能够有多个名字 * @param name the bean name to check for aliases * @return the aliases, or an empty array if none * @see #getBean */ String[] getAliases(String name); }当然,只这几个普通的接口肯定是无法定义整个spring ioc须要的类的。可是BeanFactory作为基类,保持接口的精简是很必要的,其它的BeanFactory依据特性继承该接口就可以。以下贴出关于整个BeanFactory的继承体系。
只是从类的名字。我们大概能够猜到这些类或者接口的功能。
Bean
为写成JavaBean,类必须是详细的和公共的,而且具有无參数的构造器。JavaBean 通过提供符合一致性设计模式的公共方法将内部域暴露成员属性。众所周知。属性名称符合这样的模式,其它Java 类能够通过自省机制发现和操作这些JavaBean 的属性。也就是我们经常使用的java bean对象都有例如以下几个模块组成,详细详情能够參考百度百科java bean
- 构造方法
- 属性
- 方法
- 事件
作为一个框架,常常会更具反射去动态的载入一些类,spring IOC相同也是利用了反射的技术。在spring中,会依据源数据来实例化一个java bean,而且在实例化过程中注入依赖的类。或者是调用一些初始化、销毁方法。
对于spring 容器中的bean。主要由例如以下几个属性
class |
|
name |
类名 |
scope |
生存周期 |
constructor arguments |
构造參数 |
properties |
属性 |
autowiring mode |
注入模式(byName, byType, auto) |
lazy-initialization mode |
延迟载入模式 |
initialization method |
初始化时调用的方法 |
destruction method |
摧毁时调用的方法 |
开发人员掌握要点
- bean依赖对象的注入方式(以那种方式注入bean。比方通过setter。constructor。field等)
- bean依赖对象的查找方式,也就是依据哪一种方式来寻找依赖对象(no,byName, byType,autowired)
- 选择使用那种configuration
metadata(源数据)来管理bean(主要有两种。一种是xml方式,一种是注解方式)
- 懒载入模式
- bean对象实例化、或者摧毁时调用的方法
- bean对象的生命周期(singleton,prototype,request,session,global,application。当中request,session,global,application为web专用)。
在这里面。singleton代表的是单例。也就是一个class,spring container中仅仅用一个实例。
prototype为原型模式,也就是一个class有多个实例,差别例如以下图所看到的
源代码下载
总结
- 依赖倒置法则的应用
- java bean规范的使用
- 对象生命周期
- 工厂设计模式
- 面向接口编程