jdk动态代理
- 实现
a、 一个接口
b、 一个接口的实现类
c、 一个动态代理类
只能实现接口的动态代理,通过proxy.NewProxyInstance来动态创建一个代理对象这个代理对象实现了这个接口并且继承了proxy类。
最后只会创建一个类文件
package proxy;
public interface Star
{
String sing(String name);
String dance(String name);
}
package proxy;
public class LiuDeHua implements Star
{
@Override
public String sing(String name)
{
System.out.println("给我一杯忘情水");
return "唱完" ;
}
@Override
public String dance(String name)
{
System.out.println("开心的马骝");
return "跳完" ;
}
}
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class StarProxy implements InvocationHandler
{
// 目标类,也就是被代理对象
private Object target;
public void setTarget(Object target)
{
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
// 这里可以做增强
System.out.println("收钱");
Object result = method.invoke(target, args);
return result;
}
// 生成代理类
public Object CreatProxyedObj()
{
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class StarProxy implements InvocationHandler
{
// 目标类,也就是被代理对象
private Object target;
public void setTarget(Object target)
{
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
// 这里可以做增强
System.out.println("收钱");
Object result = method.invoke(target, args);
return result;
}
// 生成代理类
public Object CreatProxyedObj()
{
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
- 核心类
proxy类
invocationHandler接口
在代理类调用方法时会动态生成一个实现了被代理的接口的实现类
Cglib动态代理
final修饰的类cglib无法进行动态代理,因为fianl修饰的类时不可边的,不能有子类的实现
通过可以继承的父类所有的公开方法,然后可以重写这些方法,在重写这些方法增强,这就时cglib的思想
最后会创建三个类文件,其中一个是当前被代理类的子类,两个是继承了FastClass类的子类
package proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor
{
/** CGLib需要代理的目标对象 */
private Object target;
//相当于JDK动态代理中的绑定
public Object getInstance(Object target) {
//给业务对象赋值
this.target = target;
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(this.target.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
}
// 实现回调方法
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("预处理——————");
proxy.invokeSuper(obj, args); //调用业务类(父类中)的方法
System.out.println("调用后操作——————");
return null;
}
}
调用》》》》》》》》》》》》》》》》》》》》》》
public static void main(String[] args)
{
int times = 1000000;
Star ldh = new LiuDeHua();
StarProxy proxy = new StarProxy();
proxy.setTarget(ldh);
long time1 = System.currentTimeMillis();
Star star = (Star)proxy.CreatProxyedObj();
long time2 = System.currentTimeMillis();
System.out.println("jdk创建时间:" + (time2 - time1));
CglibProxy proxy2 = new CglibProxy();
long time5 = System.currentTimeMillis();
Star star2 = (Star)proxy2.CreatProxyedObj(LiuDeHua.class);
long time6 = System.currentTimeMillis();
System.out.println("cglib创建时间:" + (time6 - time5));
long time3 = System.currentTimeMillis();
for (int i = 1; i <= times; i++)
{
star.sing("ss");
star.dance("ss");
}
long time4 = System.currentTimeMillis();
System.out.println("jdk执行时间" + (time4 - time3));
long time7 = System.currentTimeMillis();
for (int i = 1; i <= times; i++)
{
star2.sing("ss");
star2.dance("ss");
}
long time8 = System.currentTimeMillis();
System.out.println("cglib执行时间" + (time8 - time7));
}
cglib和jdk代理对比
1、使用情况不一样,jdk代理只有在代理对象有实现的接口时才能使用,cglib可以直接代理没有实现接口的对象
2、cglib是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理(asm是什么文末有解释),jdk动态代理时利用拦截器加上反射机制生成一个代理接口的匿名类。
3、JDK动态代理只能对实现了接口的类生成代理,而不能针对类。CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成final,对于final类或方法,是无法继承的。
4、1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,
5、在jdk6之前比使用Java反射效率要高。在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理,
6、唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
asm是什么
ASM是一个java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
binary name 是什么
提供为任何类名String在ClassLoader参数的方法必须是The Java™ Language Specification所定义的二进制名称。
有效的类名的示例包括:
"java.lang.String"
"javax.swing.JSpinner$DefaultEditor"
"java.security.KeyStore$Builder$FileBuilder$1"
"java.net.URLClassLoader$3$1"