Skip to content

Latest commit

 

History

History
98 lines (62 loc) · 4.46 KB

File metadata and controls

98 lines (62 loc) · 4.46 KB

#代理模式

##大纲:
1、代理模式定义
2、代理模式分类:
2.1、静态代理
2.2、动态代理
2.2.1、JDK代理(基于接口的代理)
2.2.2、CGlib代理(基于类继承的代理)
2.2.3、两者比较
3、spring代理方式

##1、代理模式定义
代理模式
代理模式(Proxy),指一个对象通过一个代理的对象对真正想要操作的对象(目标对象)进行操作。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
示意:客户端(client) - > 代理对象(proxy) -> 目标对象(target)

##2、代理模式分类: 代理模式分为静态代理与动态代理,
而动态代理也分为两类:基于接口的代理和基于继承的代理 两类实现的代表是:JDK代理 与 CGlib代理

###2.1、静态代理 静态代理通常表示,代理对象对目标对象进行组合,属性注入,然后继承与目标对象相同的接口,在实现的方法类,对目标对象进行调用,同时可以增加前置或后置增强操作。

###2.2、动态代理 动态代理也分为两类:基于接口的代理和基于继承的代理 两类实现的代表是:JDK代理 与 CGlib代理
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)

####2.2.1、JDK代理(基于接口的代理) JDK动态代理主要涉及java.lang.reflect包下的两个类:Proxy类和InvocationHandler接口。
JDK代理实现的三个要点:
1、通过java.lang.reflect.Proxy类来动态生成代理类
2、代理类要实现InvocationHandler接口
3、JDK代理只能基于接口进行动态代理的

其主要实现逻辑是,由InvocationHandler定义方法执行前后的增强逻辑,由Proxy类去生成一个继承自Proxy并且实现了真实对象接口的新对象–代理对象,对该代理对象的方法调用经由InvocationHandler拦截,执行增强逻辑和调用真实对象执行业务逻辑。
由于使用JdkProxySubject生成的代理类实现了接口,所以目标类中所有的方法在代理类中都存在,所有方法都可以通过代理访问。
注意:利用JDK代理方式必须有接口的存在。

优点: 因为有接口,所以使系统更加松耦合
缺点: 为每一个目标类创建接口

####2.2.2、CGlib代理(基于类继承的代理)
CGLib采用非常底层ASM字节码生成框架,使用字节码技术生成代理类。可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有的父类方法的调用,并顺势织入横切逻辑。
优点: 因为代理类与目标类是继承关系,所以不需要有接口的存在。
缺点:
因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好

###2.2.3、两者比较
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)

JDK动态代理 机制:委托机制,代理类和目标类都实现了同样的接口,InvocationHandler持有目标类,代理类委托InvocationHandler去调用目标类的原始方法
回调方式:反射
适用场景:目标类是接口类
效率:创建实例速度快, 效率瓶颈在反射调用稍慢

CGLIB动态代理 机制:继承机制,代理类继承了目标类并重写了目标方法,通过回调函数MethodInterceptor调用父类方法执行原始逻辑
回调方式:通过FastClass方法索引调用
适用场景: 非接口类,非final类,非final方法
效率: 第一次调用因为要生成多个Class对象较JDK方式慢,多次调用因为有方法索引较反射方式快。

如果实例是单例的,推荐使用CGLib方式动态代理,反之则使用JDK方式进行动态代理。

##3、spring代理方式

Spring的实例默认是单例,所以这时候使用CGLib性能高。
Spring在选择用JDK还是CGLiB的依据:
(1)当Bean实现接口时,Spring就会用JDK的动态代理
(2)当Bean没有实现接口时,Spring使用CGlib是实现
(3)可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/> 或启动类添加注解:@EnableAspectJAutoProxy(proxyTargetClass = true))