图14.Bean实例创建时序图
还有一个非常重要的部分就是建立Bean对象实例之间的关系,这也是Spring架构的核心竞争力。何时,如何创建它们之间的关系请看下面的时序图:
图15.Bean对象关系建立
3.4.3 IOC容器的扩展点
现在还有一个问题就是如何让这些Bean对象有一定的扩展性,就是可以加入用户的一些操作。那么有哪些扩展点呢?Spring又是如何调用这些扩展点呢?
对Spring的IOC来说,主要有这么几个:BeanFactoryPostProcessor,BeanPostProcessor。它们分别是在构建BeanFactory和构建Bean对象时创建。还有就是InitializingBean和DisposableBean它们分别是在Bean实例创建和销毁时被调用。用户可以实现这些接口中定义的方法,Spring就会在适当的时候调用它们。还有一个是FactoryBean是一个特殊的Bean,可以被用户更多的控制。
这些扩展点通常也是我们使用Spring来完成我们特定任务的地方,如何精通Spring就看你有没有掌握好Spring有哪些扩展点,并且如何使用它们,要知道如何使用它们就要了解Spring内在的机制。可以用下面的比喻来解释:
我们把IOC比作一个箱子,这个箱子里有若干个球的模子,可以用这些模子来造很多种不同的球,还有一个造这些球模的机器,这个机器可以产生球模。BeanFactory就是那个造球模的机器,Bean就是球模,而球模造出来的球就是Bean的实例。那么前面说的几个扩展点又在什么地方呢?
BeanFactoryPostProcessor对应到 当球模被造出来时,你将有机会对其作出适当的修改,也就是它可以帮你修改球模。而InitializingBean和DisposableBean是在球模造球的开始和结束阶段,你可以完成一些
预备和扫尾工作。BeanPostProcessor就可以让你对球模造出来的球进行适当的修正。最后还有一个FactoryBean,它是一个神奇的球模。这个球模不是预先就定型了,而是由你来确定它们的形状,既然你可以确定这个球模的形状,它造出来的球当然是你想要的球了。
3.4.4 IOC容器如何为我所用
前面介绍了Spring容器的创建过程,那Spring能为我们做什么,Spring的IOC容器又能做什么?我们使用Spring必须要首先创建IOC容器,没有它Spring无法工作,ApplicationContext.xml就是IOC容器的默认配置文件,Spring的所有特性功能都是基于这个IOC容器工作的。
IOC它实际上就是为你构建了一个魔方,Spring为你搭好了骨骼框架,这个魔方到底能变出什么好东西出来,这必须要有你的参与。那我们怎么参与?这就是前面说的有哪些扩展点,我们通过实现那些扩展点来改变Spring的通用行为。至于如何实现扩展点来得到我们想要的个性结果,Spring中有很多例子,其中AOP的实现就是Spring本事实现了其扩展点来达到它想要的特性功能,可以拿来参考。
二、 Spring中AOP特性 1. 动态代理的实现
要了解Spring的AOP就必须先了解动态代理的原理,因为AOP就是基于动态代理实现的,动态代理还要从JDK本身说起。
在JDK的java.lang.reflect包下有个Proxy类,它正是构建代理类的入口。这个类的结构如下:
图16. Proxy类结构
从上图发现最后四个是公用方法,而最后一个方法newProxyInstance就是创建代理对象的方法,这个方法的源码如下:
public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h) throws IllegalArgumentException{ if (h == null) { }
Class cl = getProxyClass(loader, interfaces); try {
Constructor cons = cl.getConstructor(constructorParams); return (Object) cons.newInstance(new Object[] { h }); throw new NullPointerException();
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
} catch (IllegalAccessException e) {
throw new InternalError(e.toString());
} catch (InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) { } }
这个方法要有三个参数:ClassLoader用于加载代理类的Loader类,通常这个Loader和被代理的类是同一个Loader类。Interfaces 是被代理的哪些接口;InvocationHandler就是用于执行除了被代理接口中方法外的用户自定义的操作,它也是用户需要代理的最终目的。用户调用目标方法都被代理到InvocationHandler类中定义的唯一方法invoke中。这在后面再详解。
throw new InternalError(e.toString());
下面看看Proxy产生代理类的过程,它构造出来的代理类到底是个什么样子呢,马上揭晓:
图17.创建代理对象时序图
从上图中可以发现正在构造代理类的是ProxyGenerator的generateProxyClass方法。ProxyGenerator类是在sun.misc包下,感兴趣的可以去看它的源码。
假如有这样一个接口,如下: 清单7. SimpleProxy类
public interface SimpleProxy { public void simpleMethod1(); public void simpleMethod2(); }
生成的代理类结构如下:
public class $Proxy2 extends java.lang.reflect.Proxy implements SimpleProxy{ java.lang.reflect.Method m0; java.lang.reflect.Method m1; java.lang.reflect.Method m2;