一.什么是代理
代理模式:显示生活中的代理。比如,买一瓶矿泉水。一种去矿泉水生产厂家购买,另一种找到矿泉水代理商购买,代理商统一去厂家进货,分销给顾客。
二.动态模式介绍
Java中代理的的便是对象或者方法。给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式。.这样做的好处是:可以在目标对象实现的功能上,增加额外的功能补充,即扩展目标对象的功能.Java种常见代理有静态代理和动态代理。
三.动态代理和静态代理
静态代理在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了。
动态代理可以在程序运行期间根据需要动态的创建代理类及其实例来完成具体的功能,下面我们结合具体实例来介绍JDK动态代理。
首先,代理对象和被代理对象需要具备相同的方法。保证两个类具有相同方法可以通过实现相同接口或者继承同一个类的方式实现。JDK自带的动态代理是前者,而cglib是后者的实现方式。
JDK动态代码示例
interface IDog{
void run();
}
//目标类
class GunDog implements IDog{
@Override
public void run() {
System.out.println("猎狗在跑");
}
}
class DogUtils{
public static void method1() {
System.out.println("增强方式一");
}
public static void method2() {
System.out.println("增强方式二");
}
}
class MyInvocationHandle 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 {
DogUtils.method1();
method.invoke(target, args);
DogUtils.method2();
return null;
}
}
//生产代理对象的工厂
class MyProxyFactory{
public static Object getProxy(Object target) {
MyInvocationHandle handle = new MyInvocationHandle();
handle.setTarget(target);
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handle);
return proxy;
}
}
public class ProxyDemo {
public static void main(String[] args) {
IDog dog = new GunDog();
IDog proxy =(IDog) MyProxyFactory.getProxy(dog);
proxy.run();
}
}`
代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能使用动态代理。
cglib代理
上面的静态代理和动态代理模式有个相同点就是都要求目标对象是实现一个接口的对象,然而并不是任何对象都会实现一个接口,也存在没有实现任何的接口的对象,
这时就可以使用继承目标类以目标对象子类的方式实现代理,这种方法就叫做:cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
使用JDK动态代理有一个限制,就是被代理的对象必须实现一个或多个接口,若想代理没有实现接口的类,就需要使用Cglib实现.所以cglib代理的类必须是final。
cglib代码示例
public class CglibProxy {
public static void main(String[] args) {
int[] arr = new int[100000];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * 1000);
}
//实例化一个增强器,也就是cglib中的一个class generator
Enhancer enhancer = new Enhancer();
//设置目标类
enhancer.setSuperclass(ArraySort2.class);
//设置拦截对象,这里直接使用匿名内部类写法
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object object , Method method, Object[] args, MethodProxy proxy) throws Throwable {
String sortName = method.getName();
switch (sortName) {
case "bubbleSort":
sortName = "冒泡排序";
break;
case "selectSort":
sortName = "选择排序";
break;
case "quickSort":
sortName = "快速排序";
break;
default:
break;
}
long start = System.currentTimeMillis();
//此处一定要使用proxy的invokeSuper方法来调用目标类的方法
proxy.invokeSuper(object, args);
long end = System.currentTimeMillis();
System.out.println("本次" + sortName + "的执行时间为: " + (end -start) + "ms");
return null;
}
});
//生成代理类并返回一个实例
ArraySort2 arraySort = (ArraySort2) enhancer.create();
arraySort.bubbleSort(arr);
arraySort.selectSort(arr);
arraySort.quickSort(arr);
}
}
class ArraySort2{
public void quickSort(int[] arr) {
Arrays.sort(arr);
}
public void selectSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = i+1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
int temp = 0;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
public void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = 0;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
}
JDK代理和cglib区别
JDK | cglib | |
---|---|---|
实现方式 | 基于接口 | 基于类 |
机制 | 利用拦截器 | 利用ASM框架 |
效率 | JDK6之后更快 | JDK6之前更快 |
总结
1、动态代理无需真实对象的差异及数量可以统一的由代理方法帮我们创建对应的真实对象实例,并引用其中的方法。
2、动态代理属于编译期代理,及运行期代理。此特点则体现了实例对象的创建由Proxy进行调派完成实例化。