Spring aop 的代理机制

Spring aop 的代理机制

Spring aop 的代理机制


Spring aop 是通过代理实现的,代理有静态代理,jdk动态代理和cglib动态代理,代理就像我们生活中的房产中介,你不直接与房主,银行接触,而是通过中介与他们沟通联系。

代理的结构如图所示:

Spring aop 的代理机制

Spring aop 的代理机制


RealSubject 和 Proxy都实现了相同的接口Subject,Proxy持有RealSubject的引用,但Client 调用 request方法时,Proxy将请求转发给RealSubject,其中可以添加各种访问控制。

但是静态代理有一个弊端,需要为每一个目标类创建一个代理类,如果需要代理的对象很多的话,就得编写相应的代理类,于是jdk动态代理出现了,它主要用了 java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。

我们先实现java.lang.reflect.InvocationHandler,添加需要的横切逻辑

public

class

AccessControl

implements

InvocationHandler

{
@Override
public

Object
invoke
(
Object
proxy
,

Method
method
,

Object
[]
args
)

throws

Throwable

{
//调用前的处理

System
.
out
.
println
(
"调用前验证"
);

Object
obj
=
method
.
invoke
(
proxy
,
args
);
//调用后的处理

System
.
out
.
println
(
"调用后处理"
);

return
obj
;
}
}

然后通过Proxy为不同的类型生成相应的代理对象。

Proxy
.
newProxyInstance
(
targertClass1
.
getClassLoader
(),
targertClass1
.
getInterfaces
(),
accessControl
);
Proxy
.
newProxyInstance
(
targertClass2
.
getClassLoader
(),
targertClass2
.
getInterfaces
(),
accessControl
);

不管targetClass有多少类型,都可以通过Proxy生成具有相同访问控制accesControl的代理对象。

从上面示例可知jdk动态代理需要被代理类实现接口(Interface),对于没有实现任何接口的目标对象,我们就要另找方法了。默认情况下,当Spring发现目标对象没有实现任何接口时,会使用CGLIB,为目标对象动态生成代理对象,其实质就是对目标对象进行继承,生成子类,子类覆盖父类的方法,在其中加入额外的访问控制,不过如果类中的方法声明为final的话,就不能对它进行扩展。

Spring 创建代理的秘密在DefaultAopProxyFactory 类中可以找到:

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
);

}

return

CglibProxyFactory
.
createCglibProxy
(

config
);

}

else

{

return

new

JdkDynamicAopProxy
(
config
);

}
}

如果isOptimize()返回true,或者proxyTargetClass属性为true,或者目标对象没有接口实现,就采用cglib动态代理,否则就用jdk动态代理。再看看JdkDynamicAopProxy中的getProxy

public

Object
getProxy
(
ClassLoader
classLoader
)

{

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
);
}

请看最后一行代码,是否有似曾相识之感。

Spring aop 仅作用于方法,如果你想对构造方法或字段作拦截处理,就要引入AspectJ,它支持在编译期间织入横切逻辑,提高运行期间的性能,但在易用性和灵活性上不如Spring aop。值得注意的是,Spring中@AspectJ注解区别的切面也是基于Spring aop 的代理机制实现的,不要被这个名称混淆了。

加Java架构师进阶交流群获取Java工程化、高性能及分布式、高性能、深入浅出。高架构。性能调优、Spring,MyBatis,Netty源码分析和大数据等多个知识点高级进阶干货的直播免费学习权限 都是大牛带飞 让你少走很多的弯路的 群号是:883922439 对了 小白勿进 最好是有开发经验

注:加群要求

1、具有工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加。

2、在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加。

3、如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的,可以加。

4、觉得自己很牛B,一般需求都能搞定。但是所学的知识点没有系统化,很难在技术领域继续突破的可以加。

5.阿里Java高级大牛直播讲解知识点,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知!


分享到:


相關文章: