2021年/03月/05日

首页回退

spring记事

开始细度spring代码,选择版本2.0,基于jdk1.5,不为别的,只为寻找大师的笔法。

背景

Java定义了一个名词叫做javabean

JavaBeans是Java中一种特殊的类,可以将多个对象封装到一个对象(bean)中。特点是可序列化,提供无参构造器,提供getter方法和setter方法访问对象的属性。名称中的“Bean”是用于Java的可重用软件组件的惯用叫法

JavaBean的种类按照功能可以划分为可视化和不可视化两类。可视化的JavaBean就是拥有GUI图形用户界面的,对最终用户是可见的,不可视化的JavaBean通常情况下用来封装业务逻辑、数据分页逻辑、数据库操作和事物逻辑等。

我们主要关注这些不可视的bean,因为spring解决的是服务端的问题。

使用一个JavaBean,需要解决构造问题,生命周期管理问题,初始化问题,于是业界发展出了IOC容器,把这些过程框架化。

核心接口

管理这些Bean的核心接口诞生了,构造和生命周期都在里面了

BeanFactory

Object getBean(String name) throws BeansException;
Object getBean(String name, Class requiredType) throws BeansException;
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

抛出的异常时运行期异常。

实现这个接口的类是XmlBeanFactory,表示我们用xml来通过配置的方式进行bean管理,如何配置呢?

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
	<bean id="aliased" class="org.springframework.beans.TestBean" name="myalias">
		<property name="name"><value>aliased</value></property>
	</bean>
</beans>

代码中加载xml

new XmlBeanFactory(new ClassPathResource("test.xml", getClass()), parent);

这里包含了一个隐含的假设,难道所有的bean都能通过xml配置出来吗?不是的,所以我们需要另一个接口

public interface FactoryBean {
	
	Object getObject() throws Exception;
	
	Class getObjectType();

	boolean isSingleton();
}

实现这个接口,我们可以编程式的构造对象,然后再配置到xml中.

XmlBeanFactory是spring的心脏,但是在应用中我们一般使用ApplicationContext这个接口,它更靠近应用层,比如在web环境中使用。根据应用环境的不同,ApplicationContext还可形成层次结构。

如何使用呢

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/org/springframework/context/support/simpleContext.xml");

面向对象编程模型中,我们有些需求需要横切一批对象的某些方法,比如我想透明的拦截一些方法进行耗时统计,业界叫做AOP技术.

因为我们的bean是从容器中获取的,于是需要引入某种代理技术把真实的对象替换掉,于是有了一个新的接口

public interface AopProxy {

	Object getProxy();

	Object getProxy(ClassLoader classLoader);

}

广义的AOP技术拦截点是很多的,spring只做到了方法级别

以上就是spring的内核,后面的所有故事都是围绕以上接口展开的。

实例化

配置文件中配置类的路径,由框架来初始化,初始化的时机可以选择框架启动的时候也可以延迟到获取bean的时候,初始化示例的核心代码是BeanUtils

	public static Object instantiateClass(Constructor ctor, Object[] args) throws BeansException {
		Assert.notNull(ctor, "Constructor must not be null");
		try {
			if (!Modifier.isPublic(ctor.getModifiers()) ||
					!Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) {
				ctor.setAccessible(true);
			}
			return ctor.newInstance(args);
		}
		catch (InstantiationException ex) {
			throw new BeanInstantiationException(ctor.getDeclaringClass(),
					"Is it an abstract class?", ex);
		}
		catch (IllegalAccessException ex) {
			throw new BeanInstantiationException(ctor.getDeclaringClass(),
					"Has the class definition changed? Is the constructor accessible?", ex);
		}
		catch (IllegalArgumentException ex) {
			throw new BeanInstantiationException(ctor.getDeclaringClass(),
					"Illegal arguments for constructor", ex);
		}
		catch (InvocationTargetException ex) {
			throw new BeanInstantiationException(ctor.getDeclaringClass(),
					"Constructor threw exception", ex.getTargetException());
		}
	}

当得到一个类的实例之后,接下来就是要进行初始化,初始化是个非常关键步骤,所以留下了扩展点

public interface BeanPostProcessor {


	Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;


	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

初始化过程中,又有一个扩展点,如果类实现了InitializingBean接口,则先执行

public interface InitializingBean {
	
	void afterPropertiesSet() throws Exception;

}

存储

默认bean的生命周期是单例,需要有个地方存起来,这个版本是放在HashMap中的,由于HashMap不是线程安全的,所以在加入的时候加了锁

	private final Map singletonCache = CollectionFactory.createLinkedMapIfPossible(16);

protected void addSingleton(String beanName, Object sharedBean) {
		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(sharedBean, "Singleton object must not be null");
		synchronized (this.singletonCache) {
			this.singletonCache.put(beanName, sharedBean);
		}
}

同时get实例的时候也是加锁的

	public Object getSingleton(String beanName) {
		synchronized (this.singletonCache) {
			return this.singletonCache.get(beanName);
		}
	}

构造过程中为了为了避免并发问题,用了一个同步的HashSet来拦截并发操作

	private final Set singletonsCurrentlyInCreation = Collections.synchronizedSet(new HashSet());


    protected void beforeSingletonCreation(String beanName) {
		if (!this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new IllegalStateException("Singleton '" + beanName + "' is already in creation");
		}
	}

单例容器主要由DefaultSingletonBeanRegistry来完成,XmlBeanFactory会继承这个类。

另外一种生命周期是prototype,每次都创建新的示例

            // Create bean instance.
			if (mergedBeanDefinition.isSingleton()) {
				sharedInstance = getSingleton(beanName, new ObjectFactory() {
					public Object getObject() throws BeansException {
						try {
							return createBean(beanName, mergedBeanDefinition, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					}
				});
				bean = getObjectForBeanInstance(sharedInstance, name, mergedBeanDefinition);
			}

			else if (mergedBeanDefinition.isPrototype()) {
				// It's a prototype -> create a new instance.
				Object prototypeInstance = null;
				try {
					beforePrototypeCreation(beanName);
					prototypeInstance = createBean(beanName, mergedBeanDefinition, args);
				}
				finally {
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, mergedBeanDefinition);
			}

动态代理

IOC容器默认生成的Bean示例对象在被使用的时候和我们平时构造的对象没有什么不一样,但是如果这些示例是由接口的,那么JDK提供了一个机制,可以生成一个和某个实例相同接口的对象,然后调用这个对象的方法的时候,我们可以植入一段拦截

Proxy类

 public static Object newProxyInstance(ClassLoader loader,
					  Class<?>[] interfaces,
					  InvocationHandler h)
	throws IllegalArgumentException
    {}

传入一个接口数组,然后实现一个InvocationHandler,就生成了一个实现了这些接口的对象,对象调用某个方法的时候,代码会走到InvocationHandler里面

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

于是我们就可以拦截java由接口的类了。

要为一个容器中的对象,生成代理怎么在spring里配置呢?

<bean id="personTarget" class="com.mycompany.PersonImpl">
    <property name="name"><value>Tony</value></property>
    <property name="age"><value>51</value></property>
</bean>

<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
    <property name="someProperty"><value>Custom string property value</value></property>
</bean>

<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor">
</bean>

<bean id="person" 
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces"><value>com.mycompany.Person</value></property>

    <property name="target"><ref local="personTarget"/></property>
    <property name="interceptorNames">
        <list>
            <value>myAdvisor</value>
            <value>debugInterceptor</value>
        </list>
    </property>
</bean>

所以AOP的代理是通过一个FactroyBean创建出来的,ProxyFactoryBean创建代理的时候需要传入接口数组,代理目标和拦截器,对应JDKProxy类,拦截器最终会实现InvocationHandler

还有种配置:

<beans>

	<!-- Simple target -->
	<bean id="target" class="org.springframework.aop.framework.adapter.ThrowsAdviceInterceptorTests$Echo">	
	</bean>
	
	<bean id="nopInterceptor" class="org.springframework.aop.interceptor.NopInterceptor">
	</bean>
	
	<bean id="countingBeforeAdvice"
		class="org.springframework.aop.framework.CountingBeforeAdvice"
	/>
	
	<bean id="throwsAdvice" 
		class="org.springframework.aop.framework.adapter.ThrowsAdviceInterceptorTests$MyThrowsHandler">	
	</bean>
	

	<bean id="throwsAdvised"
		class="org.springframework.aop.framework.ProxyFactoryBean"
	> 
			<property name="interceptorNames">
				<value>countingBeforeAdvice,nopInterceptor,throwsAdvice,target</value>
			</property>
	</bean>
	
</beans>		
	

把拦截器和目标对象都放在interceptorNames里面,最后一个元素会被当做目标对象,看代码


	/**
	 * Check the interceptorNames list whether it contains a target name as final element.
	 * If found, remove the final name from the list and set it as targetName.
	 */
	private void checkInterceptorNames() {
		if (!ObjectUtils.isEmpty(this.interceptorNames)) {
			String finalName = this.interceptorNames[this.interceptorNames.length - 1];
			if (this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
				// The last name in the chain may be an Advisor/Advice or a target/TargetSource.
				// Unfortunately we don't know; we must look at type of the bean.
				if (!finalName.endsWith(GLOBAL_SUFFIX) && !isNamedBeanAnAdvisorOrAdvice(finalName)) {
					// Must be an interceptor.
					this.targetName = finalName;
					if (logger.isDebugEnabled()) {
						logger.debug("Bean with name '" + finalName + "' concluding interceptor chain " +
								"is not an advisor class: treating it as a target or TargetSource");
					}
					String[] newNames = new String[this.interceptorNames.length - 1];
					System.arraycopy(this.interceptorNames, 0, newNames, 0, newNames.length);
					this.interceptorNames = newNames;
				}
			}
		}
	}

当这个工厂Bean返回对象的时候,会分析目标对象的接口,然后生成代理


	private synchronized Object getSingletonInstance() {
		if (this.singletonInstance == null) {
			this.targetSource = freshTargetSource();
			if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
				// Rely on AOP infrastructure to tell us what interfaces to proxy.
				setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass()));
			}
			// Eagerly initialize the shared singleton instance.
			super.setFrozen(this.freezeProxy);
			this.singletonInstance = getProxy(createAopProxy());
			// We must listen to superclass advice change events to recache the singleton
			// instance if necessary.
			addListener(this);
		}
		return this.singletonInstance;
	}

生成代理的时候用的JdkDynamicAopProxy,传入的是一个AdvisedSupport,里面包含了拦截对象和目标对象,创建代理的代码

	public Object getProxy(ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			Class targetClass = this.advised.getTargetSource().getTargetClass();
			logger.debug("Creating JDK dynamic proxy" +
					(targetClass != null ? " for [" + targetClass.getName() + "]" : ""));
		}
		Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

FactoryBean创建出来的实例会放在单独的HashMap里


	/** Cache of singleton objects created by FactoryBeans: FactoryBean name --> object */
	private final Map factoryBeanObjectCache = new HashMap();

if (beanInstance instanceof FactoryBean) {
			if (!BeanFactoryUtils.isFactoryDereference(name)) {
				// Return bean instance from factory.
				FactoryBean factory = (FactoryBean) beanInstance;
				if (logger.isDebugEnabled()) {
					logger.debug("Bean with name '" + beanName + "' is a factory bean");
				}
				// Cache object obtained from FactoryBean if it is a singleton.
				if (shared && factory.isSingleton()) {
					synchronized (this.factoryBeanObjectCache) {
						object = this.factoryBeanObjectCache.get(beanName);
						if (object == null) {
							object = getObjectFromFactoryBean(factory, beanName, mbd);
							this.factoryBeanObjectCache.put(beanName, object);
						}
					}
				}
				else {
					object = getObjectFromFactoryBean(factory, beanName, mbd);
				}
			}
			else {
	 			// The user wants the factory itself.
				if (logger.isDebugEnabled()) {
					logger.debug("Calling code asked for FactoryBean instance for name '" + beanName + "'");
				}
			}
		}

底层原理知道了之后,其实在真实使用的时候还是太繁琐,所以为了简化API,AOP开始不断的演化