
架构体系
在谈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();
}
}
}
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)