jdk动态代理
1. jdk 动态代理与spring 动态代理区别
spring有两种动态代理方式,一种就是jdk动态代理,还有就是cglib动态代理,jdk动态代理只能代理接口,cglib可以是类。jdk代理生成速度比cglib快,性能没有cglib好
2. JDK动态代理和CGLIB代理的区别
区别:
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法回前调用InvokeHandler来处理。而cglib动态答代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
3. cglib动态代理和jdk动态代理的区别与应用
jdk动态代理:需要有顶层接口才能使用,但是在只有顶层接口的时候也可以使用,常版见是权mybatis的mapper文件是代理.
cglib动态代理:可以直接代理类,使用字节码技术,不能对 final类进行继承。使用了动态生成字节码技术。
4. jdk动态代理与cglib动态代理有什么区别
1.JDK动态代理
此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。
代理模式在实际使用时需要指定具体的目标对象,如果为每个类都添加一个代理类的话,会导致类很多,同时如果不知道具体类的话,怎样实现代理模式呢?这就引出动态代理。
JDK动态代理只能针对实现了接口的类生成代理。
2.CGLIB代理
CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。
如果目标对象没有实现接口,则默认会采用CGLIB代理;
如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。
AOP包括切面(aspect)、通知(advice)、连接点(joinpoint),实现方式就是通过对目标对象的代理在连接点前后加入通知,完成统一的切面操作。
5. 静态代理,JDK动态代理和CGLib动态代理之前的区别
1、静态代理:静态代理中的代理类,需要我们自己写
JDK动态代理类实现了InvocationHandler接口。在重写的invoke方法中可以看出,动态代理的基础是反射(method.invoke(对象,参数)),还好反射看的比较多,到现在还记得。在这里需要提到的是Proxy.newProxyInstance(),这个方法。字面上的意思是 新建一个代理类的实例,这一点就和静态代理不同了。里面的参数有三个 类加载器、所有的接口,得到InvocationHandler接口的子类实例。这就是JDK动态代理,该代理有以下几种特点:
1、Interface:对于JDK Proxy,业务类是需要一个Interface的,这是一个缺陷;
2、Proxy:Proxy类是动态产生的,这个类在调用Proxy.newProxyInstance()方法之后,产生一个Proxy类的实力。实际上,这个Proxy类也是存在的,不仅仅是类的实例,这个Proxy类可以保存在硬盘上;
3、Method:对于业务委托类的每个方法,现在Proxy类里面都不用静态显示出来
4、InvocationHandler:这个类在业务委托类执行时,会先调用invoke方法。invoke方法在执行想要的代理操作,可以实现对业务方法的再包装。
以上就是JDK动态代理
3、CGLib动态代理:上面的JDK Proxy只能代理实现了接口的类,而不能实现接口的类就不能实现JDK代理。这时候就需要CGLib动态代理类
这里需要注意的是实现MethodIntercetor接口,必须导入cglib-nodep-2.1_3.jar这个包。CGLib是针对类来实现代理的,他的原理是对指定的目标生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
6. CGLIB 和 JDK生成动态代理类的区别
CGLIB 和 JDK生成动态代理类区别
jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。
cglib这种第三方类库实现的动态代理应用更加广泛,并不需要目标类基于统一的接口,且在效率上更有优势。
下面分别用2个具体例子来详细阐述
jdk生成代理类
为目标类(target)定义统一的接口类Service,这个是jdk动态代理必须的前提
publicinterfaceService{
/**
*add方法
*/
publicvoidadd();
/**
*update方法
*/
publicvoipdate();
}
2.目标类AService
{
/*
*(non-Javadoc)
*
*@seejdkproxy.Service#add()
*/
publicvoidadd(){
System.out.println("AServiceadd>>>>>>>>>>>>>>>>>>");
}
/*
*(non-Javadoc)
*
*@seejdkproxy.Service#update()
*/
publicvoipdate(){
System.out.println("AServiceupdate>>>>>>>>>>>>>>>");
}
}
3.实现动态代理类MyInvocationHandler,实现InvocationHandler接口,并且实现接口中的invoke方法。在
invoke方法中加入一些代理功能。目标类方法的执行是由mehod.invoke(target,args)这条语句完成。
{
privateObjecttarget;
MyInvocationHandler(){
super();
}
MyInvocationHandler(Objecttarget){
super();
this.target=target;
}
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
throwsThrowable{
//程序执行前加入逻辑,MethodBeforeAdviceInterceptor
System.out.println("before-----------------------------");
//程序执行
Objectresult=method.invoke(target,args);
//程序执行后加入逻辑,MethodAfterAdviceInterceptor
System.out.println("after------------------------------");
returnresult;
}
}
4.测试类,其中增强的目标对象是由Proxy.newProxyInstance(aService.getClass().getClassLoader(), aService.getClass().getInterfaces(), handler);来生成的。
publicclassTest{
publicstaticvoidmain(String[]args){
ServiceaService=newAService();
MyInvocationHandlerhandler=newMyInvocationHandler(aService);
//Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例
ServiceaServiceProxy=(Service)Proxy.newProxyInstance(aService
.getClass().getClassLoader(),aService.getClass()
.getInterfaces(),handler);
//由动态生成的代理对象来aServiceProxy代理执行程序,其中aServiceProxy符合Service接口
aServiceProxy.add();
System.out.println();
aServiceProxy.update();
}
cglib动态代理实现AOP拦截
被代理目标类,cglib不需要目标类实现接口
publicclassBase{
/**
*一个模拟的add方法
*/
publicvoidadd(){
System.out.println("add------------");
}
}实现动态代理类CglibProxy,需要实现MethodInterceptor接口,实现intercept方法。
{
publicObjectintercept(Objectobject,Methodmethod,Object[]args,
MethodProxyproxy)throwsThrowable{
//添加切面逻辑(advise),此处是在目标类代码执行之前,即为MethodBeforeAdviceInterceptor。
System.out.println("before-------------");
//执行目标类add方法
proxy.invokeSuper(object,args);
//添加切面逻辑(advise),此处是在目标类代码执行之后,即为MethodAfterAdviceInterceptor。
System.out.println("after--------------");
returnnull;
}
}获取增强的目标类的工厂Factory,其中增强的方法类对象是有Enhancer来实现的
publicclassFactory{
/**
*获得增强之后的目标类,即添加了切入逻辑advice之后的目标类
*
*@paramproxy
*@return
*/
publicstaticBasegetInstance(CglibProxyproxy){
Enhancerenhancer=newEnhancer();
enhancer.setSuperclass(Base.class);
//回调方法的参数为代理类对象CglibProxy,最后增强目标类调用的是代理类对象CglibProxy中的intercept方法
enhancer.setCallback(proxy);
//此刻,base不是单纯的目标类,而是增强过的目标类
Basebase=(Base)enhancer.create();
returnbase;
}
}测试类
publicclassTest{
publicstaticvoidmain(String[]args){
CglibProxyproxy=newCglibProxy();
//base为生成的增强过的目标类
Basebase=Factory.getInstance(proxy);
base.add();
}
}从上面2个例子,可看出cglib中目标类Base并没有实现接口,而jdk生成代理类例子中AService 实现了Service接口,所以CGLIB 和 JDK生成动态代理类的区别最大的区别就是目标类是否需要实现接口。
7. JDK动态代理 代理对象跟目标对象不同类型
public class Dog implements Animal{ //这里不知道你的接口是什么名字,就叫Animal吧
//do something
}
我猜你写的应该是:
Dog dog = ........;//你在这里用接口的实现类直接实例化,导致报错
在这里你不能直接实例化Dog对象,应该这样:
Animal animal = (Dog) ..........;
原因:不能用接口的实现类(Dog)来转换Proxy的实现类,它们是同级,应该用共同的接口来转换
8. 如何获得jdk动态代理proxy的原始类
可以在通知中(如@Before等)通过JoinPoint获取class对象(proxy):point.getTarget().getClass();
如果proxy实现接口版,再通过class.getInterfaces()即可获取原始类;
如果proxy是使用继承权父类的方式,通过class.getSuperClass()即可获取原始类。
9. JDK的动态代理为什么必须要使用接口与使用C
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在内某些情况下,一个对象不适合或容者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
接口是一种规范,定义了一组相似的行为。
通俗一些就是,当调用代理类的方法时与调用被代理类的方法时在写法上是没有任何区别的,只有接口才能保证这种一致性。
10. JDK动态代理生成的代理类在哪儿
spring代理类有用jdk的动态代理,也有用cglib包,cglib底层依赖asm包,asm同样在hibernate中也被使用,使用asm增强字节码,自动生成代理类,方法跟目标类基本一样