Spring源码剖析7:AOP实现原理详解
前言
前面写了六篇文章详细地分析了spring bean加载流程,这部分完了之后就要进入一个比较困难的部分了,就是aop的实现原理分析。为了探究aop实现原理,首先定义几个类,一个dao接口:
public interface dao {
public void select();
public void insert();
}
dao接口的实现类daoimpl:
public class daoimpl implements dao { @override public void select() { system.out.println("enter daoimpl.select()"); } @override public void insert() { system.out.println("enter daoimpl.insert()"); } }
定义一个timehandler,用于方法调用前后打印时间,在aop中,这扮演的是横切关注点的角色:
public class timehandler { public void printtime() { system.out.println("currenttime:" + system.currenttimemillis()); } }
定义一个xml文件aop.xml:
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <bean id="daoimpl" class="org.xrq.action.aop.daoimpl" /> <bean id="timehandler" class="org.xrq.action.aop.timehandler" /> <aop:config proxy-target-class="true"> <aop:aspect id="time" ref="timehandler"> <aop:pointcut id="addallmethod" expression="execution(* org.xrq.action.aop.dao.*(..))" /> <aop:before method="printtime" pointcut-ref="addallmethod" /> <aop:after method="printtime" pointcut-ref="addallmethod" /> </aop:aspect> </aop:config> </beans>
写一段测试代码testaop.java:
public class testaop { @test public void testaop() { applicationcontext ac = new classpathxmlapplicationcontext("spring/aop.xml"); dao dao = (dao)ac.getbean("daoimpl"); dao.select(); } }
代码运行结果就不看了,有了以上的内容,我们就可以根据这些跟一下代码,看看spring到底是如何实现aop的。
aop实现原理——找到spring处理aop的源头
有很多朋友不愿意去看aop源码的一个很大原因是因为找不到aop源码实现的入口在哪里,这个确实是。不过我们可以看一下上面的测试代码,就普通bean也好、aop也好,最终都是通过getbean方法获取到bean并调用方法的,getbean之后的对象已经前后都打印了timehandler类printtime()方法里面的内容,可以想见它们已经是被spring容器处理过了。
既然如此,那无非就两个地方处理:
加载bean定义的时候应该有过特殊的处理
getbean的时候应该有过特殊的处理
因此,本文围绕【1.加载bean定义的时候应该有过特殊的处理】展开,先找一下到底是哪里spring对aop做了特殊的处理。代码直接定位到defaultbeandefinitiondocumentreader的parsebeandefinitions方法:
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); } }
正常来说,遇到
因为之前把整个xml解析为了org.w3c.dom.document,org.w3c.dom.document以树的形式表示整个xml,具体到每一个节点就是一个node。 首先第2行从
config–>configbeandefinitionparser
aop bean定义加载——根据织入方式将
首先获取具体的parser,因为当前节点是
重点先提一下第6行的代码,该行代码的具体实现不跟了但它非常重要,configureautoproxycreator方法的作用我用几句话说一下: 向spring容器注册了一个beanname为org.springframework.aop.config.internalautoproxycreator的bean定义,可以自定义也可以使用spring提供的(根据优先级来)
从第20行~第37行的循环开始关注这个方法。这个for循环有一个关键的判断就是第22行的ifadvicenode判断,看下ifadvicenode方法做了什么: 即这个for循环只用来处理
接着,如果是上述五种标签之一,那么进入第33行~第34行的parseadvice方法: 方法主要做了三件事: 根据织入方式(before、after这些)创建rootbeandefinition,名为advicedef即advice定义 首先可以看到,创建的abstractbeandefinition实例是rootbeandefinition,这和普通bean创建的实例为genericbeandefinition不同。然后进入第6行的getadviceclass方法看一下: 既然创建bean定义,必然该bean定义中要对应一个具体的class,不同的切入方式对应不同的class: before对应aspectjmethodbeforeadvice
aop bean定义加载——将名为advicedef的rootbeandefinition转换成名为advisordefinition的rootbeandefinition 这里相当于将上一步生成的rootbeandefinition包装了一下,new一个新的rootbeandefinition出来,class类型是org.springframework.aop.aspectj.aspectjpointcutadvisor。 第4行~第7行的代码是用于判断
aop bean定义加载——将beandefinition注册到defaultlistablebeanfactory中 最后一步就是将beandefinition注册到defaultlistablebeanfactory中了,代码就是前面configbeandefinitionparser的parseadvice方法的最后一部分了: ... 第2行获取注册的名字beanname,和
第3行向defaultlistablebeanfactory中注册,beanname已经有了,剩下的就是bean定义,bean定义的解析流程之前已经看过了,就不说了。 aop bean定义加载——aopnamespacehandler处理
省略号部分表示是解析的是
第5行~第7行的代码构建了一个aspect标签组件定义,并将apsect标签组件定义推到parsecontext即解析工具上下文中,这部分代码不是关键。 第9行的代码拿到所有
第2行~第3行的代码获取
第8行的代码推送一个pointcutentry,表示当前spring上下文正在解析pointcut标签。 第9行的代码创建pointcut的bean定义,之后再看,先把其他方法都看一下。 第10行的代码不管它,最终从nullsourceextractor的extractsource方法获取source,就是个null。 第12行~第18行的代码用于注册获取到的bean定义,默认pointcutbeanname为
如果
第23行~第25行的代码,finally块在
最后回头来一下第9行代码createpointcutdefinition的实现,比较简单: 关键就是注意一下两点:
上篇文章说了,org.springframework.aop.aspectj.autoproxy.aspectjawareadvisorautoproxycreator这个类是spring提供给开发者的aop的核心类,就是aspectjawareadvisorautoproxycreator完成了【类/接口–>代理】的转换过程,首先我们看一下aspectjawareadvisorautoproxycreator的层次结构: 这里最值得注意的一点是最左下角的那个方框,我用几句话总结一下: aspectjawareadvisorautoproxycreator是beanpostprocessor接口的实现类 代理对象实例化—-判断是否为
初始化之前是第16行的applybeanpostprocessorsbeforeinitialization方法,初始化之后即29行的applybeanpostprocessorsafterinitialization方法: 这里调用每个beanpostprocessor的postprocessbeforeinitialization方法。按照之前的分析,看一下abstractautoproxycreator的postprocessafterinitialization方法实现: 跟一下第5行的方法wrapifnecessary: 第2行~第11行是一些不需要生成代理的场景判断,这里略过。首先我们要思考的第一个问题是:哪些目标对象需要生成代理?因为配置文件里面有很多bean,肯定不能对每个bean都生成代理,因此需要一套规则判断bean是不是需要生成代理,这套规则就是第14行的代码getadvicesandadvisorsforbean: 顾名思义,方法的意思是为指定class寻找合适的advisor。 第2行代码,寻找候选advisors,根据上文的配置文件,有两个候选advisor,分别是
跳过第3行的代码,先看下第4行的代码extendadvisors方法,之后再重点看一下第3行的代码。第4行的代码extendadvisors方法作用是向候选advisor链的开头(也就是list.get(0)的位置)添加一个org.springframework.aop.support.defaultpointcutadvisor。 第3行代码,根据候选advisors,寻找可以使用的advisor,跟一下方法实现: 整个方法的主要判断都围绕canapply展开方法: 第一个参数advisor的实际类型是aspectjpointcutadvisor,它是pointcutadvisor的子类,因此执行第7行的方法: 这个方法其实就是拿当前advisor对应的expression做了两层判断: 目标类必须满足expression的匹配规则
代理对象实例化—-为
第14行拿到
第4行~第6行new出了一个proxyfactory,proxy,顾名思义,代理工厂的意思,提供了简单的方式使用代码获取和配置aop代理。 第8行的代码做了一个判断,判断的内容是
第17行~第28行的代码没什么看的必要,向proxyfactory中添加一些参数而已。重点看第30行proxyfactory.getproxy(this.proxyclassloader)这句: 实现代码就一行,但是却明确告诉我们做了两件事情: 创建aopproxy接口实现类
代理对象实例化—-创建aopproxy接口实现类 前面的部分没什么必要看,直接进入重点即createaopproxy方法: 平时我们说aop原理三句话就能概括: 对类生成代理使用cglib proxyconfig的isoptimize方法为true,这表示让spring自己去优化而不是用户指定
proxy-target-class没有配置或者proxy-target-class=”false”,返回jdkdynamicaopproxy
代理对象实例化—-通过getproxy方法获取
cglib2aopproxy生成代理的代码就不看了,对cglib不熟悉的朋友可以看cglib及其基本使用一文。 jdkdynamicaopproxy生成代理的方式稍微看一下: public object getproxy(classloader classloader) { 最终通过第7行的proxy.newproxyinstance方法获取接口/类对应的代理对象,proxy是jdk原生支持的生成代理的方式。 代理方法调用原理 由于jdkdynamicaopproxy本身实现了invocationhandler接口,因此具体代理前后处理的逻辑在invoke方法中: 第11行~第18行的代码,表示equals方法与hashcode方法即使满足expression规则,也不会为之产生代理内容,调用的是jdkdynamicaopproxy的equals方法与hashcode方法。至于这两个方法是什么作用,可以自己查看一下源代码。 第19行~第23行的代码,表示方法所属的class是一个接口并且方法所属的class是advisedsupport的父类或者父接口,直接通过反射调用该方法。 第27行~第30行的代码,是用于判断是否将代理暴露出去的,由
第41行的代码,获取advisedsupport中的所有拦截器和动态拦截器列表,用于拦截方法,具体到我们的实际代码,列表中有三个object,分别是: chain.get(0):exposeinvocationinterceptor,这是一个默认的拦截器,对应的原advisor为defaultpointcutadvisor 第51行~第56行的代码,如果拦截器列表不为空,按照注释的意思,需要一个reflectivemethodinvocation,并通过proceed方法对原方法进行拦截,proceed方法感兴趣的朋友可以去看一下,里面使用到了递归的思想对chain中的object进行了层层的调用。 下面我们来看一下cglib代理的方式,这里需要读者去了解一下cglib以及其创建代理的方式: 这里将拦截器链封装到了dynamicadvisedinterceptor中,并加入了callback,dynamicadvisedinterceptor实现了cglib的methodinterceptor,所以其核心逻辑在intercept方法中: 这里我们看到了与jdk动态代理同样的获取拦截器链的过程,并且cglibmethodinvokcation继承了我们在jdk动态代理看到的reflectivemethodinvocation,但是并没有重写其proceed方法,只是重写了执行目标方法的逻辑,所以整体上是大同小异的。 到这里,整个spring 动态aop的源码就分析完了,spring还支持静态aop,这里就不过多赘述了,有兴趣的读者可以查阅相关资料来学习。 微信公众号【黄小斜】作者是蚂蚁金服 java 工程师,专注于 javapublic beandefinition parsecustomelement(element ele, beandefinition containingbd) {
string namespaceuri = getnamespaceuri(ele);
namespacehandler handler = this.readercontext.getnamespacehandlerresolver().resolve(namespaceuri);
if (handler == null) {
error("unable to locate spring namespacehandler for xml schema namespace [" + namespaceuri + "]", ele);
return null;
}
return handler.parse(ele, new parsercontext(this.readercontext, this, containingbd));
}
aspectj-autoproxy–>aspectjautoproxybeandefinitionparser
scoped-proxy–>scopedproxybeandefinitiondecorator
spring-configured–>springconfiguredbeandefinitionparser
接着,就是第8行的代码,利用aopnamespacehandler的parse方法,解析解析增强器advisor
上面经过分析,已经找到了spring是通过aopnamespacehandler处理的aop,那么接着进入aopnamespacehandler的parse方法源代码:public beandefinition parse(element element, parsercontext parsercontext) {
return findparserforelement(element, parsercontext).parse(element, parsercontext);
}
public beandefinition parse(element element, parsercontext parsercontext) {
compositecomponentdefinition compositedef =
new compositecomponentdefinition(element.gettagname(), parsercontext.extractsource(element));
parsercontext.pushcontainingcomponent(compositedef);
configureautoproxycreator(parsercontext, element);
list<element> childelts = domutils.getchildelements(element);
for (element elt: childelts) {
string localname = parsercontext.getdelegate().getlocalname(elt);
if (pointcut.equals(localname)) {
parsepointcut(elt, parsercontext);
}
else if (advisor.equals(localname)) {
parseadvisor(elt, parsercontext);
}
else if (aspect.equals(localname)) {
parseaspect(elt, parsercontext);
}
}
parsercontext.popandregistercontainingcomponent();
return null;
}
spring默认提供的是org.springframework.aop.aspectj.autoproxy.aspectjawareadvisorautoproxycreator,这个类是aop的核心类,留在下篇讲解
在这个方法里面也会根据配置proxy-target-class和expose-proxy,设置是否使用cglib进行代理以及是否暴露最终的代理。private void parseaspect(element aspectelement, parsercontext parsercontext) {
string aspectid = aspectelement.getattribute(id);
string aspectname = aspectelement.getattribute(ref);
try {
this.parsestate.push(new aspectentry(aspectid, aspectname));
list<beandefinition> beandefinitions = new arraylist<beandefinition>();
list<beanreference> beanreferences = new arraylist<beanreference>();
list<element> declareparents = domutils.getchildelementsbytagname(aspectelement, declare_parents);
for (int i = method_index; i < declareparents.size(); i++) {
element declareparentselement = declareparents.get(i);
beandefinitions.add(parsedeclareparents(declareparentselement, parsercontext));
}
// we have to parse "advice" and all the advice kinds in one loop, to get the
// ordering semantics right.
nodelist nodelist = aspectelement.getchildnodes();
boolean advicefoundalready = false;
for (int i = 0; i < nodelist.getlength(); i++) {
node node = nodelist.item(i);
if (isadvicenode(node, parsercontext)) {
if (!advicefoundalready) {
advicefoundalready = true;
if (!stringutils.hastext(aspectname)) {
parsercontext.getreadercontext().error(
"<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
aspectelement, this.parsestate.snapshot());
return;
}
beanreferences.add(new runtimebeanreference(aspectname));
}
abstractbeandefinition advisordefinition = parseadvice(
aspectname, i, aspectelement, (element) node, parsercontext, beandefinitions, beanreferences);
beandefinitions.add(advisordefinition);
}
}
aspectcomponentdefinition aspectcomponentdefinition = createaspectcomponentdefinition(
aspectelement, aspectid, beandefinitions, beanreferences, parsercontext);
parsercontext.pushcontainingcomponent(aspectcomponentdefinition);
list<element> pointcuts = domutils.getchildelementsbytagname(aspectelement, pointcut);
for (element pointcutelement : pointcuts) {
parsepointcut(pointcutelement, parsercontext);
}
parsercontext.popandregistercontainingcomponent();
}
finally {
this.parsestate.pop();
}
}
private boolean isadvicenode(node anode, parsercontext parsercontext) {
if (!(anode instanceof element)) {
return false;
}
else {
string name = parsercontext.getdelegate().getlocalname(anode);
return (before.equals(name) || after.equals(name) || after_returning_element.equals(name) ||
after_throwing_element.equals(name) || around.equals(name));
}
}
private abstractbeandefinition parseadvice(
string aspectname, int order, element aspectelement, element adviceelement, parsercontext parsercontext,
list<beandefinition> beandefinitions, list<beanreference> beanreferences) {
try {
this.parsestate.push(new adviceentry(parsercontext.getdelegate().getlocalname(adviceelement)));
// create the method factory bean
rootbeandefinition methoddefinition = new rootbeandefinition(methodlocatingfactorybean.class);
methoddefinition.getpropertyvalues().add("targetbeanname", aspectname);
methoddefinition.getpropertyvalues().add("methodname", adviceelement.getattribute("method"));
methoddefinition.setsynthetic(true);
// create instance factory definition
rootbeandefinition aspectfactorydef =
new rootbeandefinition(simplebeanfactoryawareaspectinstancefactory.class);
aspectfactorydef.getpropertyvalues().add("aspectbeanname", aspectname);
aspectfactorydef.setsynthetic(true);
// register the pointcut
abstractbeandefinition advicedef = createadvicedefinition(
adviceelement, parsercontext, aspectname, order, methoddefinition, aspectfactorydef,
beandefinitions, beanreferences);
// configure the advisor
rootbeandefinition advisordefinition = new rootbeandefinition(aspectjpointcutadvisor.class);
advisordefinition.setsource(parsercontext.extractsource(adviceelement));
advisordefinition.getconstructorargumentvalues().addgenericargumentvalue(advicedef);
if (aspectelement.hasattribute(order_property)) {
advisordefinition.getpropertyvalues().add(
order_property, aspectelement.getattribute(order_property));
}
// register the final advisor
parsercontext.getreadercontext().registerwithgeneratedname(advisordefinition);
return advisordefinition;
}
finally {
this.parsestate.pop();
}
}
将上一步创建的rootbeandefinition写入一个新的rootbeandefinition,构造一个新的对象,名为advisordefinition,即advisor定义
将advisordefinition注册到defaultlistablebeanfactory中
下面来看做的第一件事createadvicedefinition方法定义:private abstractbeandefinition createadvicedefinition(
element adviceelement, parsercontext parsercontext, string aspectname, int order,
rootbeandefinition methoddef, rootbeandefinition aspectfactorydef,
list<beandefinition> beandefinitions, list<beanreference> beanreferences) {
rootbeandefinition advicedefinition = new rootbeandefinition(getadviceclass(adviceelement, parsercontext));
advicedefinition.setsource(parsercontext.extractsource(adviceelement));
advicedefinition.getpropertyvalues().add(aspect_name_property, aspectname);
advicedefinition.getpropertyvalues().add(declaration_order_property, order);
if (adviceelement.hasattribute(returning)) {
advicedefinition.getpropertyvalues().add(
returning_property, adviceelement.getattribute(returning));
}
if (adviceelement.hasattribute(throwing)) {
advicedefinition.getpropertyvalues().add(
throwing_property, adviceelement.getattribute(throwing));
}
if (adviceelement.hasattribute(arg_names)) {
advicedefinition.getpropertyvalues().add(
arg_names_property, adviceelement.getattribute(arg_names));
}
constructorargumentvalues cav = advicedefinition.getconstructorargumentvalues();
cav.addindexedargumentvalue(method_index, methoddef);
object pointcut = parsepointcutproperty(adviceelement, parsercontext);
if (pointcut instanceof beandefinition) {
cav.addindexedargumentvalue(pointcut_index, pointcut);
beandefinitions.add((beandefinition) pointcut);
}
else if (pointcut instanceof string) {
runtimebeanreference pointcutref = new runtimebeanreference((string) pointcut);
cav.addindexedargumentvalue(pointcut_index, pointcutref);
beanreferences.add(pointcutref);
}
cav.addindexedargumentvalue(aspect_instance_factory_index, aspectfactorydef);
return advicedefinition;
}
private class getadviceclass(element adviceelement, parsercontext parsercontext) {
string elementname = parsercontext.getdelegate().getlocalname(adviceelement);
if (before.equals(elementname)) {
return aspectjmethodbeforeadvice.class;
}
else if (after.equals(elementname)) {
return aspectjafteradvice.class;
}
else if (after_returning_element.equals(elementname)) {
return aspectjafterreturningadvice.class;
}
else if (after_throwing_element.equals(elementname)) {
return aspectjafterthrowingadvice.class;
}
else if (around.equals(elementname)) {
return aspectjaroundadvice.class;
}
else {
throw new illegalargumentexception("unknown advice kind [" + elementname + "].");
}
}
after对应aspectjafteradvice
after-returning对应aspectjafterreturningadvice
after-throwing对应aspectjafterthrowingadvice
around对应aspectjaroundadvice
createadvicedefinition方法剩余逻辑没什么,就是判断一下标签里面的属性并设置一下相应的值而已,至此
下面我们看一下第二步的操作,将名为advicedef的rootbeand转换成名为advisordefinition的rootbeandefinition,跟一下上面一部分configbeandefinitionparser类parseadvice方法的第26行~32行的代码:rootbeandefinition advisordefinition = new rootbeandefinition(aspectjpointcutadvisor.class);
advisordefinition.setsource(parsercontext.extractsource(adviceelement));
advisordefinition.getconstructorargumentvalues().addgenericargumentvalue(advicedef);
if (aspectelement.hasattribute(order_property)) {
advisordefinition.getpropertyvalues().add(
order_property, aspectelement.getattribute(order_property));
}
// register the final advisor
parsercontext.getreadercontext().registerwithgeneratedname(advisordefinition);
...
跟一下registerwithgeneratedname方法的实现:public string registerwithgeneratedname(beandefinition beandefinition) {
string generatedname = generatebeanname(beandefinition);
getregistry().registerbeandefinition(generatedname, beandefinition);
return generatedname;
}
解析切面的过程
回到configbeandefinitionparser的parseaspect方法:private void parseaspect(element aspectelement, parsercontext parsercontext) {
...
aspectcomponentdefinition aspectcomponentdefinition = createaspectcomponentdefinition(
aspectelement, aspectid, beandefinitions, beanreferences, parsercontext);
parsercontext.pushcontainingcomponent(aspectcomponentdefinition);
list<element> pointcuts = domutils.getchildelementsbytagname(aspectelement, pointcut);
for (element pointcutelement : pointcuts) {
parsepointcut(pointcutelement, parsercontext);
}
parsercontext.popandregistercontainingcomponent();
}
finally {
this.parsestate.pop();
}
}
private abstractbeandefinition parsepointcut(element pointcutelement, parsercontext parsercontext) {
string id = pointcutelement.getattribute(id);
string expression = pointcutelement.getattribute(expression);
abstractbeandefinition pointcutdefinition = null;
try {
this.parsestate.push(new pointcutentry(id));
pointcutdefinition = createpointcutdefinition(expression);
pointcutdefinition.setsource(parsercontext.extractsource(pointcutelement));
string pointcutbeanname = id;
if (stringutils.hastext(pointcutbeanname)) {
parsercontext.getregistry().registerbeandefinition(pointcutbeanname, pointcutdefinition);
}
else {
pointcutbeanname = parsercontext.getreadercontext().registerwithgeneratedname(pointcutdefinition);
}
parsercontext.registercomponent(
new pointcutcomponentdefinition(pointcutbeanname, pointcutdefinition, expression));
}
finally {
this.parsestate.pop();
}
return pointcutdefinition;
}
如果
第20行~第21行的代码向解析工具上下文中注册一个pointcut组件定义protected abstractbeandefinition createpointcutdefinition(string expression) {
rootbeandefinition beandefinition = new rootbeandefinition(aspectjexpressionpointcut.class);
beandefinition.setscope(beandefinition.scope_prototype);
beandefinition.setsynthetic(true);
beandefinition.getpropertyvalues().add(expression, expression);
return beandefinition;
}
这样一个流程下来,就解析了aop为bean生成代理的时机分析
postprocessbeforeinitialization方法与postprocessafterinitialization方法实现在父类abstractautoproxycreator中
postprocessbeforeinitialization方法是一个空实现
逻辑代码在postprocessafterinitialization方法中
基于以上的分析,将bean生成代理的时机已经一目了然了:在每个bean初始化之后,如果需要,调用aspectjawareadvisorautoproxycreator中的postprocessbeforeinitialization为bean生成代理。
上文分析了bean生成代理的时机是在每个bean初始化之后,下面把代码定位到bean初始化之后,先是abstractautowirecapablebeanfactory的initializebean方法进行初始化:protected object initializebean(final string beanname, final object bean, rootbeandefinition mbd) {
if (system.getsecuritymanager() != null) {
accesscontroller.doprivileged(new privilegedaction<object>() {
public object run() {
invokeawaremethods(beanname, bean);
return null;
}
}, getaccesscontrolcontext());
}
else {
invokeawaremethods(beanname, bean);
}
object wrappedbean = bean;
if (mbd == null || !mbd.issynthetic()) {
wrappedbean = applybeanpostprocessorsbeforeinitialization(wrappedbean, beanname);
}
try {
invokeinitmethods(beanname, wrappedbean, mbd);
}
catch (throwable ex) {
throw new beancreationexception(
(mbd != null ? mbd.getresourcedescription() : null),
beanname, "invocation of init method failed", ex);
}
if (mbd == null || !mbd.issynthetic()) {
wrappedbean = applybeanpostprocessorsafterinitialization(wrappedbean, beanname);
}
return wrappedbean;
}
public object applybeanpostprocessorsafterinitialization(object existingbean, string beanname)
throws beansexception {
object result = existingbean;
for (beanpostprocessor beanprocessor : getbeanpostprocessors()) {
result = beanprocessor.postprocessafterinitialization(result, beanname);
if (result == null) {
return result;
}
}
return result;
}
public object postprocessafterinitialization(object bean, string beanname) throws beansexception {
if (bean != null) {
object cachekey = getcachekey(bean.getclass(), beanname);
if (!this.earlyproxyreferences.contains(cachekey)) {
return wrapifnecessary(bean, beanname, cachekey);
}
}
return bean;
}
protected object wrapifnecessary(object bean, string beanname, object cachekey) {
if (this.targetsourcedbeans.contains(beanname)) {
return bean;
}
if (this.nonadvisedbeans.contains(cachekey)) {
return bean;
}
if (isinfrastructureclass(bean.getclass()) || shouldskip(bean.getclass(), beanname)) {
this.nonadvisedbeans.add(cachekey);
return bean;
}
// create proxy if we have advice.
object[] specificinterceptors = getadvicesandadvisorsforbean(bean.getclass(), beanname, null);
if (specificinterceptors != do_not_proxy) {
this.advisedbeans.add(cachekey);
object proxy = createproxy(bean.getclass(), beanname, specificinterceptors, new singletontargetsource(bean));
this.proxytypes.put(cachekey, proxy.getclass());
return proxy;
}
this.nonadvisedbeans.add(cachekey);
return bean;
}
protected list<advisor> findeligibleadvisors(class beanclass, string beanname) {
list<advisor> candidateadvisors = findcandidateadvisors();
list<advisor> eligibleadvisors = findadvisorsthatcanapply(candidateadvisors, beanclass, beanname);
extendadvisors(eligibleadvisors);
if (!eligibleadvisors.isempty()) {
eligibleadvisors = sortadvisors(eligibleadvisors);
}
return eligibleadvisors;
}
public static list<advisor> findadvisorsthatcanapply(list<advisor> candidateadvisors, class<?> clazz) {
if (candidateadvisors.isempty()) {
return candidateadvisors;
}
list<advisor> eligibleadvisors = new linkedlist<advisor>();
for (advisor candidate : candidateadvisors) {
if (candidate instanceof introductionadvisor && canapply(candidate, clazz)) {
eligibleadvisors.add(candidate);
}
}
boolean hasintroductions = !eligibleadvisors.isempty();
for (advisor candidate : candidateadvisors) {
if (candidate instanceof introductionadvisor) {
// already processed
continue;
}
if (canapply(candidate, clazz, hasintroductions)) {
eligibleadvisors.add(candidate);
}
}
return eligibleadvisors;
}
public static boolean canapply(advisor advisor, class<?> targetclass, boolean hasintroductions) {
if (advisor instanceof introductionadvisor) {
return ((introductionadvisor) advisor).getclassfilter().matches(targetclass);
}
else if (advisor instanceof pointcutadvisor) {
pointcutadvisor pca = (pointcutadvisor) advisor;
return canapply(pca.getpointcut(), targetclass, hasintroductions);
}
else {
// it doesn't have a pointcut so we assume it applies.
return true;
}
}
public static boolean canapply(pointcut pc, class<?> targetclass, boolean hasintroductions) {
if (!pc.getclassfilter().matches(targetclass)) {
return false;
}
methodmatcher methodmatcher = pc.getmethodmatcher();
introductionawaremethodmatcher introductionawaremethodmatcher = null;
if (methodmatcher instanceof introductionawaremethodmatcher) {
introductionawaremethodmatcher = (introductionawaremethodmatcher) methodmatcher;
}
set<class> classes = new hashset<class>(classutils.getallinterfacesforclassasset(targetclass));
classes.add(targetclass);
for (class<?> clazz : classes) {
method[] methods = clazz.getmethods();
for (method method : methods) {
if ((introductionawaremethodmatcher != null &&
introductionawaremethodmatcher.matches(method, targetclass, hasintroductions)) ||
methodmatcher.matches(method, targetclass)) {
return true;
}
}
}
return false;
}
目标类中的方法必须满足expression的匹配规则,当然这里方法不是全部需要满足expression的匹配规则,有一个方法满足即可
如果以上两条都满足,那么容器则会判断该代理对象实例化过程
上文分析了为protected object wrapifnecessary(object bean, string beanname, object cachekey) {
if (this.targetsourcedbeans.contains(beanname)) {
return bean;
}
if (this.nonadvisedbeans.contains(cachekey)) {
return bean;
}
if (isinfrastructureclass(bean.getclass()) || shouldskip(bean.getclass(), beanname)) {
this.nonadvisedbeans.add(cachekey);
return bean;
}
// create proxy if we have advice.
object[] specificinterceptors = getadvicesandadvisorsforbean(bean.getclass(), beanname, null);
if (specificinterceptors != do_not_proxy) {
this.advisedbeans.add(cachekey);
object proxy = createproxy(bean.getclass(), beanname, specificinterceptors, new singletontargetsource(bean));
this.proxytypes.put(cachekey, proxy.getclass());
return proxy;
}
this.nonadvisedbeans.add(cachekey);
return bean;
}
protected object createproxy(
class<?> beanclass, string beanname, object[] specificinterceptors, targetsource targetsource) {
proxyfactory proxyfactory = new proxyfactory();
// copy our properties (proxytargetclass etc) inherited from proxyconfig.
proxyfactory.copyfrom(this);
if (!shouldproxytargetclass(beanclass, beanname)) {
// must allow for introductions; can't just set interfaces to
// the target's interfaces only.
class<?>[] targetinterfaces = classutils.getallinterfacesforclass(beanclass, this.proxyclassloader);
for (class<?> targetinterface : targetinterfaces) {
proxyfactory.addinterface(targetinterface);
}
}
advisor[] advisors = buildadvisors(beanname, specificinterceptors);
for (advisor advisor : advisors) {
proxyfactory.addadvisor(advisor);
}
proxyfactory.settargetsource(targetsource);
customizeproxyfactory(proxyfactory);
proxyfactory.setfrozen(this.freezeproxy);
if (advisorsprefiltered()) {
proxyfactory.setprefiltered(true);
}
return proxyfactory.getproxy(this.proxyclassloader);
}
public object getproxy(classloader classloader) {
return createaopproxy().getproxy(classloader);
}
通过aopproxy接口的实现类的getproxy方法获取
就从这两个点出发,分两部分分析一下。
看一下createaopproxy()方法的实现,它位于defaultaopproxyfactory类中:protected final synchronized aopproxy createaopproxy() {
if (!this.active) {
activate();
}
return getaopproxyfactory().createaopproxy(this);
}
public aopproxy createaopproxy(advisedsupport config) throws aopconfigexception {
if (config.isoptimize() || config.isproxytargetclass() || hasnousersuppliedproxyinterfaces(config)) {
class targetclass = config.gettargetclass();
if (targetclass == null) {
throw new aopconfigexception("targetsource cannot determine target class: " +
"either an interface or a target is required for proxy creation.");
}
if (targetclass.isinterface()) {
return new jdkdynamicaopproxy(config);
}
if (!cglibavailable) {
throw new aopconfigexception(
"cannot proxy target class because cglib2 is not available. " +
"add cglib to the class path or specify proxy interfaces.");
}
return cglibproxyfactory.createcglibproxy(config);
}
else {
return new jdkdynamicaopproxy(config);
}
}
对接口生成代理使用jdk原生的proxy
可以通过配置文件指定对接口使用cglib生成代理
这三句话的出处就是createaopproxy方法。看到默认是第19行的代码使用jdk自带的proxy生成代理,碰到以下三种情况例外:
proxyconfig的isproxytargetclass方法为true,这表示配置了proxy-target-class=”true”
proxyconfig满足hasnousersuppliedproxyinterfaces方法执行结果为true,这表示
在进入第2行的if判断之后再根据目标
proxy-target-class=”true”或者
当然,不管是jdkdynamicaopproxy还是cglib2aopproxy,advisedsupport都是作为构造函数参数传入的,里面存储了具体的advisor。
其实代码已经分析到了jdkdynamicaopproxy和cglib2aopproxy,剩下的就没什么好讲的了,无非就是看对这两种方式生成代理的熟悉程度而已。
if (logger.isdebugenabled()) {
logger.debug("creating jdk dynamic proxy: target source is " + this.advised.gettargetsource());
}
class[] proxiedinterfaces = aopproxyutils.completeproxiedinterfaces(this.advised);
finddefinedequalsandhashcodemethods(proxiedinterfaces);
return proxy.newproxyinstance(classloader, proxiedinterfaces, this);
}
这边解释一下第5行和第6行的代码,第5行代码的作用是拿到所有要代理的接口,第6行代码的作用是尝试寻找这些接口方法里面有没有equals方法和hashcode方法,同时都有的话打个标记,寻找结束,equals方法和hashcode方法有特殊处理。
前面已经详细分析了为接口/类生成代理的原理,生成代理之后就要调用方法了,这里看一下使用jdkdynamicaopproxy调用方法的原理。public object invoke(object proxy, method method, object[] args) throws throwable {
methodinvocation invocation;
object oldproxy = null;
boolean setproxycontext = false;
targetsource targetsource = this.advised.targetsource;
class targetclass = null;
object target = null;
try {
if (!this.equalsdefined && aoputils.isequalsmethod(method)) {
// the target does not implement the equals(object) method itself.
return equals(args[0]);
}
if (!this.hashcodedefined && aoputils.ishashcodemethod(method)) {
// the target does not implement the hashcode() method itself.
return hashcode();
}
if (!this.advised.opaque && method.getdeclaringclass().isinterface() &&
method.getdeclaringclass().isassignablefrom(advised.class)) {
// service invocations on proxyconfig with the proxy config...
return aoputils.invokejoinpointusingreflection(this.advised, method, args);
}
object retval;
if (this.advised.exposeproxy) {
// make invocation available if necessary.
oldproxy = aopcontext.setcurrentproxy(proxy);
setproxycontext = true;
}
// may be null. get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetsource.gettarget();
if (target != null) {
targetclass = target.getclass();
}
// get the interception chain for this method.
list<object> chain = this.advised.getinterceptorsanddynamicinterceptionadvice(method, targetclass);
// check whether we have any advice. if we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a methodinvocation.
if (chain.isempty()) {
// we can skip creating a methodinvocation: just invoke the target directly
// note that the final invoker must be an invokerinterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
retval = aoputils.invokejoinpointusingreflection(target, method, args);
}
else {
// we need to create a method invocation...
invocation = new reflectivemethodinvocation(proxy, target, method, args, targetclass, chain);
// proceed to the joinpoint through the interceptor chain.
retval = invocation.proceed();
}
// massage return value if necessary.
if (retval != null && retval == target && method.getreturntype().isinstance(proxy) &&
!rawtargetaccess.class.isassignablefrom(method.getdeclaringclass())) {
// special case: it returned "this" and the return type of the method
// is type-compatible. note that we can't help if the target sets
// a reference to itself in another returned object.
retval = proxy;
}
return retval;
}
finally {
if (target != null && !targetsource.isstatic()) {
// must have come from targetsource.
targetsource.releasetarget(target);
}
if (setproxycontext) {
// restore old proxy.
aopcontext.setcurrentproxy(oldproxy);
}
}
}
chain.get(1):methodbeforeadviceinterceptor,用于在实际方法调用之前的拦截,对应的原advisor为aspectjmethodbeforeadvice
chain.get(2):aspectjafteradvice,用于在实际方法调用之后的处理
第45行~第50行的代码,如果拦截器列表为空,很正常,因为某个类/接口下的某个方法可能不满足expression的匹配规则,因此此时通过反射直接调用该方法。cglib代理实现
后端技术栈:springboot、ssm全家桶、mysql、分布式、中间件、微服务,同时也懂点投资理财,坚持学习和写作,相信终身学习的力量!关注公众号后回复”架构师“即可领取
java基础、进阶、项目和架构师等免费学习资料,更有数据库、分布式、微服务等热门技术学习视频,内容丰富,兼顾原理和实践,另外也将赠送作者原创的java学习指南、java程序员面试指南等干货资源