架构体系
在谈spring bean的重新加载前,首先我们来看看spring ioc容器。
spring ioc容器主要功能是完成对bean的创建、依赖注入和管理等功能,而这些功能的实现是有下面几个组件完成的:
Resource:对资源的抽象,不同的资源有不同的实现,例如:ClasspathResource、FileSystemResource。。。
BeanDefinition:描述一个具体的bean,里面包含了bean的一些基本信息,不同类型的bean也有不同的实现类:ScannedGenericBeanDefinition、RootBeanDefinition
BeanDefinitionReader:将资源转化BeanDefinition的一个接口,针对不同类型的资源有不同的实现:XmlBeanDefinitionReader、PropertiesBeanDefinitionReader
BeanFactory:bean工厂,实现了对bean的创建、注入于与管理
ApplicationContext:应用上下文,持有BeanFactory对象
BeanFactory
SpringBean的创建是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者管理对象间的依赖关系提供了很多便利和基础服务,在Spring中有许多的IOC容器的实现供用户选择和使用
BeanFactory定义了工厂类基本的操作,BeanFactory有三个直属子类:AutowireCapableBeanFactory,HierarchicalBeanFactory,ListableBeanFactory;这个三个子类定义了spring对不同bean的处理。
spring对不同的场景提供了不同实现,下面的类
AutowireCapableBeanFactory:定义了对bean的创建与注入
HierarchicalBeanFactory:定义了对结构化的bean进行处理
ListableBeanFactory:定义了对bean的匹配查找
DefaultListableBeanFactory:以上三个接口的默认实现。提供了bean定义的注册与缓存和对単例bean的初始化
BeanDefinition
BeanDefinition是对一个具体的bean的描述,包括了initMethodName、destroyMethodName、资源文件等 。
bean 创建注入
ioc容器的初始化过程包括对资源的定位、资源的解析、beanDefinition的注册、bean的创建与注入。
refresh是整个ioc容器创建的入口
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // 实现了对资源的定位,解析,beanDefinition的注册 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // 初始scope为singleton和不是延迟加载的bean finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
resource的解析和beanDefinition的注册
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } //beanDefintion的注册 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 将beanDefintion注册到beanFactory BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
单例bean的创建入口。
public void preInstantiateSingletons() throws BeansException { List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames); // 创建bean 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>() { @Override public Boolean run() { return ((SmartFactoryBean<?>) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } else { getBean(beanName); } } } }
spring在内部维护了一个缓存用来保存已创建的单例bean,所以spring在创建bean的时候会首先在缓存里看有没有,如果没有则创建,这同时也为循环依赖提供了支持,spring不对是原型的bean提供循环依赖支持
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; // 首先从缓存里取 Object sharedInstance = getSingleton(beanName); //省略其它代码 。。。 。。。 。。。 }
创建bean
BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); }
bean注入过程,根据注入类型注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; }
一般我们在项目中使用@Autowired注解是由AutowiredAnnotationBeanPostProcessor这个类实现注入的
public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { //获取注入元数据 //AutowiredAnnotationBeanPostProcessor里面维护了一个变量用户缓存注入元数据 InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs);//依赖注入 } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); } return pvs; } public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable { Collection<InjectedElement> elementsToIterate = (this.checkedElements != null ? this.checkedElements : this.injectedElements); if (!elementsToIterate.isEmpty()) { boolean debug = logger.isDebugEnabled(); for (InjectedElement element : elementsToIterate) { if (debug) { logger.debug("Processing injected element of bean '" + beanName + "': " + element); } element.inject(target, beanName, pvs); } } } protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { Field field = (Field) this.member; try { Object value; if (this.cached) { value = resolvedCachedArgument(beanName, this.cachedFieldValue); } else { DependencyDescriptor desc = new DependencyDescriptor(field, this.required); desc.setContainingClass(bean.getClass()); Set<String> autowiredBeanNames = new LinkedHashSet<String>(1); TypeConverter typeConverter = beanFactory.getTypeConverter(); //获取依赖的bean,会递归调用getBean()方法,直到获取到的bean没有任何依赖 value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); synchronized (this) { if (!this.cached) { if (value != null || this.required) { this.cachedFieldValue = desc; registerDependentBeans(beanName, autowiredBeanNames); if (autowiredBeanNames.size() == 1) { String autowiredBeanName = autowiredBeanNames.iterator().next(); if (beanFactory.containsBean(autowiredBeanName)) { if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { this.cachedFieldValue = new RuntimeBeanReference(autowiredBeanName); } } } } else { this.cachedFieldValue = null; } this.cached = true; } } } if (value != null) { ReflectionUtils.makeAccessible(field); field.set(bean, value);//通过反射设置值 } } catch (Throwable ex) { throw new BeanCreationException("Could not autowire field: " + field, ex); } } }
spring bean的重新加载
大家都知道我们在eclipse debug模式运行应用程序时,当我们修改了方法体内的代码时,是不需要马上重启就能生效的(其中的原理暂时没找到)。现在我们要实现的spring bean的重新加载,不仅可实现对方法体外做了代码修改能生效,也不需要在dubug模式运行。要实现这样的功能,首先我们要收集到spring为我们创建了哪些bean,然后监听bean对应的字节码文件有没有发生改变,当发生改变时,重新加载。
spring bean的收集
spring在创建bean时,使用了beanDefinition来描述一个bean,并把beanDefinition维护在DefaultListableBeanFactory.beanDefinitionMap。收集bean 可以在spring容器启动完成时获取beanFactory并持有,创建一个ApplicationListener的实现类
public class Startup implements ApplicationListener<ContextRefreshedEvent> { public void onApplicationEvent(ContextRefreshedEvent event) { BeanWatch beanWatch = new BeanWatch(event.getApplicationContext()); beanWatch.start(); } }
获取需要监听的bean
private Map<String, ClassBeanDefinition> findWatchBean() { Map<String, ClassBeanDefinition> watchBeans = new HashMap<String, ClassBeanDefinition>(); for (String name : applicationContext.getBeanDefinitionNames()) {// 获取spring管理的所有bean名称 Object bean = applicationContext.getBean(name);// 获取bean BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(name); Class<?> clazz = bean.getClass(); URL resource = clazz.getResource(""); File file = new File(resource.getPath() + clazz.getSimpleName() + ".class"); ClassBeanDefinition classBeanDefinition = new ClassBeanDefinition(); classBeanDefinition.setBeanDefinition(beanDefinition); classBeanDefinition.setFile(file); classBeanDefinition.setBeanName(name); watchBeans.put(name, classBeanDefinition); } return watchBeans; }
字节码重新加载
收集完字节码文件之后要做的就是,对文件的监听,当一个文件发生改变时,我们需要做的是重新将改变的class文件加载进来,但spring为我们创建bean时已经将class文件加载进来了,由于java的类加载机制,一个类只会加载一次,所以我们需要自定义一个classLoader去动态的加载我们需要的类
public class DynamicClassLoader extends ClassLoader { public DynamicClassLoader(ClassLoader parent) { super(parent); } public Class<?> loadClass(File file,String className) throws ClassNotFoundException { try { InputStream input = new FileInputStream(file); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int data = input.read(); while (data != -1) { buffer.write(data); data = input.read(); } input.close(); byte[] classData = buffer.toByteArray(); return defineClass(className, classData, 0, classData.length); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } }
重新加载bean
当我们拥有了最新的字节码时,我们需要把bean工厂维护的beanDefinition修改为最新的字节码并把spring工厂对应的bean缓存删除,然后再调用beanFactory的getBean()方法
public void reloadBean(ClassBeanDefinition classBeanDefinition, Class<?> clazz, DynamicClassLoader classLoader) { try { //只针对ScannedGenericBeanDefinition做实现 ScannedGenericBeanDefinition beanDefinition = (ScannedGenericBeanDefinition) beanDefinitionMap.get(classBeanDefinition.getBeanName()); beanDefinition.setBeanClass(clazz); // 删除beanFactory缓存的bean factoryBeanObjectCache.remove(classBeanDefinition.getBeanName()); // 删除合并的BeanDefinitions mergedBeanDefinitions.remove(classBeanDefinition.getBeanName()); Object bean = beanFactory.getBean(classBeanDefinition.getBeanName()); reloadReferenceClass(classBeanDefinition, bean, classLoader); } catch (Exception e) { e.printStackTrace(); } }
到此我们已经把改变的bean重新加载进来,但是,如果该bean是别的bean的一个依赖,那么我们需要为有依赖了改变的bean重新进行注入。由于我们前面将bean加载进来时,bean的字节码是被不同的ClassLoader重新加载进来的,如果此时直接将有依赖的bean从缓存删掉,然后再调用getBean()会导致spring在为bean注入时抛ClassCastException,所以我们需要维护一个ClassLoader对象用来作为每次加载新字节码的ClassLoader的父ClassLoader。
public void reloadReferenceClass(ClassBeanDefinition classBeanDefinition, Object bean, DynamicClassLoader parent) { Class<?> typeClass = bean.getClass(); Set<String> injectCacheKeys = findReferenceClass(typeClass.getName()); DynamicClassLoader classLoader = new DynamicClassLoader(parent); Thread.currentThread().setContextClassLoader(classLoader); for (String cacheKey : injectCacheKeys) {// 将引用了该bean的类重新创建 Map<String, InjectionMetadata> map = (Map<String, InjectionMetadata>) Reflections.getFieldValue(autowiredAnnotationBeanPostProcessor, "injectionMetadataCache"); InjectionMetadata metadata = map.get(cacheKey); ClassBeanDefinition definition = beanDefinitions.get(cacheKey); try { Class<?> clazz = classLoader.loadClass(definition.getFile(), definition.getBeanDefinition().getBeanClassName()); Field[] fields = clazz.getDeclaredFields(); Collection<InjectedElement> injectedElements = (Collection<InjectedElement>) Reflections.getFieldValue(metadata, "injectedElements"); Set<InjectedElement> checkedElements = (Set<InjectedElement>) Reflections.getFieldValue(metadata, "checkedElements"); Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : injectedElements); for (Field f : fields) { Class<?> type = f.getType(); if (type.isInstance(bean)) { for (InjectedElement element : elementsToIterate) { Field field = (Field) element.getMember(); if (field.getType().getName().equals(f.getType().getName())) { Reflections.setFieldValue(element, "member", f);//修改spring维护的InjectedElement属性 break; } } } } parentClassLoader = parent; reloadBean(definition, clazz, classLoader); } catch (Exception e) { e.printStackTrace(); } } }