spring-ioc Spring IOC

       在了解一个东西之前,通常我们都会先去思考下,这个东西是用于做什么的?比方我们看书,通常都喜欢浏览下简单介绍或者文件夹,编程也一样。所以想要学习IOC的设计,那么我们就必需要明确,IOC主要是用于做例如以下几件事情的:
      1.实例化java bean
      2.管理容器中的java bean的生命周期(init,run,destroy等)
      3.管理java bean的创建方式。比方原型模式,单列模式
      4.管理java bean的会话周期,类似http中的request,session,appliaction等概念
      5.设置java bean之间的依赖关系
有了这个整体的思路。我们再去查看spring的相关源代码。就会清晰非常多。
        
       在Spring Framework简单介绍中介绍了spring的总体框架,这篇文章主要介绍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组成       

       IOC是一个容器,将全部的java bean对象交给IOC来管理,其它类在初始化时。依赖的类不是自动new一个。而是由IOC主动注入,这个过程恰好与传统模式相反,所以我们称之为控制反转。因为控制反转这个词语很的抽象,所以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图
spring-ioc
Spring IOC
       
     从图中能够看到,图中一种由三个元素构成:configuration metadata(源信息),business object,spring container。由三者能够产生一个fully configured system(可执行的系统)。当中business object为业务逻辑代码,也就是前面样例中的UserDaoImpl,UserController。configuration metadata为源信息。也就是告诉spring container怎样去实例化bean,注入bean依赖的类,在前面的样例中,@Controller。@Repository,@Autowired就是告诉spring container UserController与UserDaoImpl为java bean对象,然后UserController依赖于IUserDao。spring container拿到这些源信息后,就会尝试去完毕任务。假设成功了,那么系统就准备就绪了。

IOC的实现

       有了前面的内容,想必读者对IOC有了一定的了解。IOC主要就是做例如以下的几件事:
       1.拿到源信息
       2.初始化容器,初始化时。自己主动注入java bean之间的依赖对象
       那么spring是怎样初始化容器,而且自己主动注入java bean之间的依赖对象呢?作为一个开发人员,相比读者也能够推測到,spring做的事情应该是先实例化一个bean,然后查看这个bean的依赖关系,假设这个bean没有依赖,那么实例化成功,增加一个集合中(比方使用Map<String,Object>);假设这个bean有依赖。那么查看容器中是否已经有对应的bean,假设有,直接注入,bean实例化成功;没有就先将bean缓存起来,继续实例化其它bean;当全部bean都初始化完成后,在解决先前缓存起来bean之间的依赖关系。以下是依据这个思路画的一个简单流程图,图有点丑,大家莫见怪
spring-ioc
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       

      以下深入到源代码处去观察下spring container是怎样完毕任务的。

在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的继承体系。
    spring-ioc
Spring IOC
        
       这里面还有几个类没有截图进来,详细的大家能够使用Eclipse快捷键F4查看下BeanFactory的继承体系。

只是从类的名字。我们大概能够猜到这些类或者接口的功能。

Bean

       IOC是一个容器。管理系统的所有java bean对象。那么什么是java bean呢?JavaBean 是一种JAVA语言写成的可重用组件。

为写成JavaBean,类必须是详细的和公共的,而且具有无參数的构造器

。JavaBean 通过提供符合一致性设计模式的公共方法将内部域暴露成员属性。众所周知。属性名称符合这样的模式,其它Java 类能够通过自省机制发现和操作这些JavaBean 的属性。也就是我们经常使用的java bean对象都有例如以下几个模块组成,详细详情能够參考百度百科java bean
  • 构造方法
  • 属性
  • 方法
  • 事件
       在spring中。因为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

摧毁时调用的方法

 开发人员掌握要点   

       在IOC模块,使用者主要须要掌握的就是例如以下几点:
  • 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有多个实例,差别例如以下图所看到的

      以下的表格为spring bean可配置的属性
spring-ioc
Spring IOC
spring-ioc
Spring IOC       

源代码下载       

      介绍完IOC的一些背景知识,以下使用详细的代码演示下系统是怎样执行的。在demo中。使用注解的方式来管理configuration metadata(源信息)。为了让project最小化,默认使用maven来管理系统的依赖jar。详细的大家能够直接下载源码。github

总结

      在spring container中,大量使用了设计模式。须要好好学习下。当然,也不不过设计模式,还包括了面向对象汇总经常使用的一些概念。

  • 依赖倒置法则的应用
  • java bean规范的使用
  • 对象生命周期
  • 工厂设计模式
  • 面向接口编程