动态代理的实现有两种方式:JDK动态代理和Cglib,这两种方式有什么区别:
1)JDK动态代理要求被代理类需要实现一个接口类即必须有implement
2)cglib可以对普通类进行代理,由于cglib底层是通过继承方式实现,所以不能代理final类型的类
一、JDK动态代理
1.1、创建一个接口
public interface Fruit {
String getName();
String getColor();
Float getPrice();
String toValue();
}
1.2、实现这个接口
package com.atguigu.function;
public class Apple implements Fruit {
private String name;
private String color;
private Float price;
public Apple(String name, String color, Float price) {
this.name = name;
this.color = color;
this.price = price;
}
@Override
public String getName() {
System.out.println("name="+name);
return name;
}
@Override
public String getColor() {
System.out.println("color="+color);
return color;
}
@Override
public Float getPrice() {
System.out.println("price="+price);
return price;
}
@Override
public String toValue() {
String value = "Apple{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", price=" + price +
'}';
System.out.println(value);
return value;
}
}
1.3、创建代理对象
public class DynamicProxy {
public static void main(String[] args) {
//创建被代理对象
Apple apple = new Apple("apple", "red", 20.0f);
//创建代理对象,类型为接口类型
Fruit appleProxy = (Fruit) Proxy.newProxyInstance(Fruit.class.getClassLoader(), new Class[]{Fruit.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName() == "toValue") {//只对toValue增强
System.out.println("........");
Object o = method.invoke(apple, args);
System.out.println("--------");
return o;
} else {
return method.invoke(apple, args);
}
}
});
appleProxy.toValue();//被增强了
appleProxy.getColor();//没有被增加
}
}
二、cglib动态代理
JDK proxy实现动态代理有一个缺陷,就是要求被代理类要实现一个接口。但是有些场景的类是没有实现接口的,那么就可以使用cglib来实现。cglib底层实现,是通过字节码增加技术。
引入依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
定义一个普通类Apple
public class Apple {
private String name = "苹果";
private String color = "红色";
private Float price = 10.0f;
public Apple() {//默认构造函数必须提供
}
public Apple(String name, String color, Float price) {
this.name = name;
this.color = color;
this.price = price;
}
public String getName() {
System.out.println("name="+name);
return name;
}
public String getColor() {
System.out.println("color="+color);
return color;
}
public Float getPrice() {
System.out.println("price="+price);
return price;
}
public String toValue() {
String value = "Apple{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", price=" + price +
'}';
System.out.println(value);
return value;
}
}
动态代理Cglib应用
public class CglibApp {
public static void main(String[] args) {
Apple target = new Apple("苹果", "黄色", 15.0f); //用于方式一
Enhancer enhancer = new Enhancer(); //工具类
enhancer.setSuperclass(Apple.class); //父类
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before....");
//方式一, 直接通过java放射机制,需要提供一个被代理对象,比如手动new出来的对象
//Object result = method.invoke(target, args);
//方式二, 通过proxy方式,不需要被代理对象 推荐
Object result = proxy.invokeSuper(obj, args);
System.out.println("After....");
return result;
}
});
Apple proxyApple = (Apple)enhancer.create();
proxyApple.toValue();
}
}
cglib底层使用了ASM库,ASM 是直接字节码,除非对字节码结构非常熟悉,否则不推荐直接使用ASM库
三、总结
这里简单对比了一下,JDK动态代理和Cglib实现的动态代理,希望能启到抛砖引玉的作用