IoC:
context是总管家。总领全局
context创建一个bean工厂,一个解析工具(如xmlReader)。先让解析工具去完成对xml或者注解中bean的解析,对于每个bean节点,提取出其中的名称,类型、属性来构建出一个beandefinition(bd),并存放到解析工具的map中,之后创建这个map中的bd全部移到bean工厂的map中,然后扫描出所有类型为bean初始化前置/后置处理器的bean,此时就要把它们创建好,并把它们都加到bean工厂的前置/后置处理列表中。
此时bean工厂中有了所有的bean的bd(但bean本身还没创建,除了前置/后置处理器bean)
(tiny中是全部bean都在这里创建,而在spring中,bean创建可以等到用户第一次getbean时,再触发下面的动作)
之后进行bean的创建,进行context的onrefresh,在bean工厂中遍历map,创建bean的实例,并且对每个bean实例做如下工作:
创建后把bean实例和它的bd绑定起来(把它赋给bd的一个属性),并且从bd中取出之前设定的一些属性,给bean赋上。然后对从bean工厂中取出之前加入到前置处理器列表中的bean,使用这些处理器bean对当前的这个bean做前置处理;然后进行这个bean的初始化方法(指定的init-method),然后取出之前加入到后置处理器列表中的bean,使用这些处理器bean对当前的这个bean做后置处理(比如aop就是在这一步发挥作用,检测这个bean的类型是不是符合要拦截处理的类型,如果是,则创建用一个该类代理类型的bean代替当前的这个bean返回); 做完前置/后置处理后都会返回bean(这个bean可能已经被修改了),再次把这个最终经过前后置处理的bean重新与bd绑定(之前绑定的就作废了)。(真正的spring中还有给每个bean设置关于容器感知,名称感知,context感知之类的功能)
(如果对于特定类型的bean要执行特定的前置/后置处理,只需在处理器中判断bean的类型,满足再处理,否则就把传入的bean原样返回即可)
此时,bean的初始化就完成了,获取bean的话,就通过context得到bean工厂,再从bean工厂中通过要获取的bean的类型或名称得到bd,再从bd得到与之绑定的bean。
AOP
有一个后置处理器叫AspectJAwareAdvisorAutoProxyCreator(简称apc),它的作用是在bean的后置处理时如果需要创建代理,则创建代理来代替原始bean返回
有一个类叫TargetSource,它可以封装一个其他类的实例对象,类型,以及它实现和继承的类型/接口集合,相当于是某个实例对象的信息组合。
一个类叫AdvisedSupport(具体实现是proxyFactory),它是一个aop的核心类型,它有targetsource的成员变量,有方法拦截器的成员变量,有方法匹配器的成员变量。
advisors实际上是包含所有需要代理的类的名单,需要拦截的方法的名单,以及所有的方法拦截器。
advisors由多个advisor组成,每个advisor包含一个pointcut成员,一个advice成员。
pointcut定义了一组规则,包括符合条件的类型名规则,符合拦截的方法名规则。(术语是切点)
advice就是一个方法拦截器.(其实就是执行额外的逻辑代码的工具) (术语是通知)
(这里advisor的术语就是aspect,即切面,实际上就是切点和通知的综合体)
每个advisor也是一个bean,它在spring中实际上就是注解了@AspectJ的类的实例,其pointcut和advice可能都是自己。(而且为了保证advisor必须在其他实例创建之前就创建好,每次有一个bean进入创建代理的后置处理器时,会从容器获得所有的advisor(利用getBeansForType),如果有某个advisor还没创建,则优先创建它。因此会保证如果一个bean需要被代理,则其advisor一定在它用之前就创建好)
当有一个bean要进行apc的后置处理的时候,遍历所有的advisor,如果不符合所有的advisor类型规则,则直接返回bean;如果发现符合其中一个advisor的类型规则,进入下一步:(真正的spring中使用拦截链,也就是说可以有多个advisor匹配当前的bean,调用方法的时候会一个挨一个调用)
创建一个advisedSupport
·根据这个bean去创建一个它的targetSource,并且把这个targetSource设置给advisedSupport的成员
·把当前的advisor的方法规则(方法匹配器)设置给advisedSupport
·把当前advisor的方法拦截规则(方法拦截器)设置给advisedSupport
使用advisedSupport生成一个代理工厂,该代理工厂拥有advisedSupport的成员变量,并且这个代理工厂是一个调用处理器(InvocationHandler)。
使用代理工厂去生成一个当前这个bean的代理对象。如果用jdk动态代理的话,使用
Proxy.newProxyInstance(当前类的类型加载器, bean的所有实现和继承的类型/接口集合, 调用处理器(也就是生成它的代理工厂))来得到一个代理对象,这个代理对象拥有所有bean的同名方法,当调用代理对象的一个方法时,会调用它的调研处理器的invoke方法,并且会把bean的原本该名称的方法、bean对象,参数都传入invoke
,在调用处理器(即代理工厂)的invoke方法中,使用它的成员advisedSupport的方法匹配规则来判断当前调用的这个方法是不是需要拦截的,如果不是则直接调用bean的原来的方法;如果是需要拦截的,则使用advisedSupport的方法拦截器,去执行具体的拦截器的额外逻辑代码(这里还涉及到一个MethodInvocation,但它实际上就是对一个方法、对象、参数的包装,只是为了方便打包传递,从调用处理器传递到拦截器,没有额外的用途),当然这个额外的逻辑代码中也可以调用bean原来的方法,也可以去做一些额外的操作。
生成代理后返回,则此时代理对象就取代了原本的bean成为了bean容器中针对原来的bean类型的合法代言人了,别的地方不论是通过原本的类型,还是设置的名称,获得的都是这个代理,而原来的bean就只存在于代理对象的调用处理器中的advisedSupport中的targetSource中(层层包裹,外部是无法得到这个bean的)。
另:
生成代理对象的方式有jdk动态代理,还有其他一些,如Cglib2等,但原理都是一样的。
注意,jdk动态代理生成的对象只能转成实际类实现的接口类型的对象,而无法转成实在的类的对象(而cglib能)
例如,A implements I
jdk动态代理创建好的代理proxy只能强转成I类型的,而不能强转成A类型的。
注意,InvocationHandler的invoke方法,传递过来的是proxy,而不是原始对象,所以如果要运行原本实例的方法(method.invoke),需要在InvocationHandler中保存原本的实例